これはドキュメントやチュートリアルではありません。クロックインして小さなメモだけを録音することで、C言語を学ぶように自分自身を監督しているだけです。何か間違いがありましたら、ご指摘いただきありがとうございます!!!
1つは、アレイ
- 配列内の添え字2で要素への割り当てを開始します
// C99
char array_char[5] = {
[2] = 'o', 'l', 'l'};
for (int i = 0; i < 5; ++i) {
PRINT_CHAR(array_char[i]);
}
第二に、文字列
- 文字列と文字配列はまだ異なります。文字列は\ 0で終わります
3つ目は、関数の配列タイプパラメータです。
- 関数のパラメータが配列の場合、配列の長さとしてパラメータを渡す必要があります。2次元配列を渡す場合は、1次元配列の長さを決定します。
四、ポインター
#include <stdio.h>
int main() {
int a;
scanf("%d", &a);//111
int *p = &a;
return 0;
}
メモリの各部分にはアドレスがマークされています。例として上記の場合を取り上げます。
- まず、写真のp、&p、a、&aの内容を取得できます
- pの内容にはaのアドレスが含まれ、&aはaのアドレスでもあります(ナンセンス、ハハハ)。これは0x65fe14で、メモリ内のこの領域の内容は
これは16進数で、10進数に変換すると入力した111です。
-
このとき、pのあるスペースである&pを取り出し、0x65fe18を取り出します。
-
次に、私たちが学んだことによれば、メモリ番号0x65fe18のブロックの内容は0x65fe14(aのアドレス)であり、結果は、次の図に示すように、実際にそうであることを証明します。
案の定、理論を見ても現実は見えませんが、自分で現実と真実を見始めるべきです。
5つの読み取り専用ポインター変数と読み取り専用変数ポインター
- constは左連想であることを覚えておいてください
- もう一度覚えておいてください* pはスペースの内容を指し、pはスペース自体です
(1)ある場合
int a;
int b;
//const修饰指针*,p的空间不能改变
int * const p = &a;
//p = &b;报错
(2)ある場合
int a;
int b;
//const修饰int,p的内容不能变
int const *p = &a;
//*p = 11;报错
6、使用できないポインタ
- ポインタのアドレスを気軽に定義できず、ハードコーディングできません
- NULLはマクロですが、NULLポインターに値を割り当てないでください
- グローバルポインタを使用して、破棄される自動的に型指定された変数を指すなど、ワイルドポインタを排除します
セブン、特別なポインター
- ポインタの加算と減算の数は、実際には、加算と減算のポインタが指すコンテンツタイプのバイト数の対応する倍数です。以下はケースです。
#include <stdio.h>
int main() {
int a = 5;
int *p = &a;
//当前环境下int为4个字节
printf("%d\n",sizeof(int));//4
printf("%hx\n",p);//fe0c
p += 1;
printf("%hx\n",p);//fe10,刚好位移4个字节
double b = 5.0;
double *q = &b;
//当前环境下double为8个字节
printf("%d\n",sizeof(double));//8
printf("%hx\n",q);//fe00
q += 1;
printf("%hx\n",q);//fe08,刚好8个字节
return 0;
}
- 配列もポインタですが、スペースを変更するために使用することはできません。これは* constと同等です。
8.左右の値
- 左の値はメモリスペース、右の値は値です
- * pは左側に配置されたスペース、右側に配置された値は値です
9つの動的メモリ割り当て
- 標準ライブラリ<stdlib.h>を導入する必要があります
- マロックの作成、自由な破壊
- ダーティデータを避けるために初期化することを忘れないでください
- callocは最初に0に直接クリアされます
- reallocは再割り当てされますが、追加されたものは空になりません
- メモリの割り当てに失敗した場合は、nullポインタを返します
- 無料でNULLにしてください
10.一般的なポインタ使用エラー
- ポインタを離すのを忘れた
- 解放されたポインタにアクセスします
- 範囲外で使用する
- メモリポインタを変更する
11、関数ポインタ
- 関数にはアドレスがあるため、関数にはポインターがあります
- 配列のように、関数名は実際には関数のアドレスです
- typedefを使用して関数タイプを定義できます
#include <stdio.h>
#include <stdlib.h>
#include <io_utils.h>
// 1
int *(f1(int, double));
// 2
int (*f2)(int, double);
// 3
int *(*f3)(int, double);
// 4
// int (*f4)(int, double)[];
// 5
// int (*f5)[](int, double);
typedef int (*Func)(int, double);
typedef int Boolean;
typedef int *IntPtr;
typedef int IntArray[];
int Add(int left, double right) {
return (int) (left + right);
}
void InitPointer(int **ptr, int length, int default_value) {
*ptr = malloc(sizeof(int) * length);
for (int i = 0; i < length; ++i) {
(*ptr)[i] = default_value;
}
}
int main() {
int a;
IntPtr p;
IntArray players = {
1,3,4,5};
PRINT_HEX(&main);
PRINT_HEX(&InitPointer);
void (*func)(int **ptr, int length, int default_value) = &InitPointer;
func(&p, 10, 0);
InitPointer(&p, 10, 0);
(*func)(&p, 10, 0);
(*InitPointer)(&p, 10, 0);
PRINT_INT_ARRAY(p, 10);
free(p);
Func func1 = &Add;
int result = func1(1, 3.0);
PRINT_INT(result);
return 0;
}
十二、混乱
- 可変長はc99以降でのみサポートされるため、MSVCは変数として配列長をサポートしませんが、gccは個別の拡張を行うことに注意してください
- c90の配列は、const読み取り専用属性でさえなく、定数が必要です。
- ctrl + wを使用して、クリオンでのオペレーターの優先順位を表示します