編集:「BIGMISTAKE」セクションを更新しました。
Cスタイル(C ++とは異なります!)のtypedefに関する簡単なレッスン、およびその理由と使用方法。
まず、基本的なtypedefのトリックです。
typedef int* int_pointer;
int_pointer ip1;
int *ip2;
int a; // Just a variable
ip1 = &a; // Sets the pointer to a
ip2 = &a; // Sets the pointer to a
*ip1 = 4; // Sets a to 4
*ip2 = 4; // Sets a to 4
ip1とip2は同じ型です。つまり、ip1の宣言に*を入れていなくても、type-intへのポインターです。その*は代わりに宣言に含まれていました。
トピックの切り替え。あなたは配列を次のように宣言することについて話します
int array1[4];
実行時にこれを動的に行うには、次のようにします。
int *array2 = malloc(sizeof(int) * 4);
int a = 4;
array1[0] = a;
array2[0] = a; // The [] implicitly dereferences the pointer
では、ポインタの配列が必要な場合はどうでしょうか。次のようになります。
int *array1[4];
int a;
array1[0] = &a; // Sets array[0] to point to variable a
*array1[0] = 4; // Sets a to 4
その配列を動的に割り当てましょう。
int **array2 = malloc(sizeof(int *) * 4);
array2[0] = &a; // [] implicitly dereferences
*array2[0] = 4; // Sets a to 4
int**に注意してください。これは、pointer-topointer-to-intを意味します。必要に応じて、ポインターtypedefを使用できます。
typedef int* array_of_ints;
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
array3[0] = &a; // [] implicitly dereferences
*array3[0] = 4; // Sets a to 4
その最後の宣言に*が1つしかないことを確認してください。これは、そのうちの1つが「typedef内」にあるためです。最後の宣言で、int(int *)への4つのポインターで構成されるサイズ4の配列ができました。
ここで演算子の優先順位を指摘することが重要です。間接参照演算子[]は、*演算子よりも優先されます。完全に明確にするために、私たちが行っているのはこれです:
*(array3[0]) = 4;
それでは、トピックをstructsとtypedefsに変更しましょう。
struct foo { int a; }; // Declares a struct named foo
typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar'
なぜ匿名の構造体をtypedefするのですか?さて、読みやすさのために!
struct foo a; // Declares a variable a of type struct foo
bar b; // Notice how you don't have to put 'struct' first
関数を宣言しています...
funca(struct foo* arg1, bar *arg2);
arg2の前に「struct」を配置する必要がなかった方法をご覧ください。
これで、使用する必要のあるコードがこの方法で構造を定義していることがわかります。
typedef struct { } * foo_pointers;
これは、以前にポインタの配列を実行した方法に類似しています。
typedef int* array_of_ints;
並べて比較する
typedef struct { } * foo_pointers;
typedef int* array_of_ints;
唯一の違いは、1つは構造体{}に対するものであり、もう1つはintに対するものであるということです。
foo_pointersを使用すると、fooへのポインターの配列を次のように宣言できます。
foo_pointers fooptrs[4];
これで、アクセスできない匿名構造への4つのポインターを格納する配列ができました。
トピックスイッチ!
残念ながら、あなたの先生は間違いを犯しました。上記のfoo_pointers型のsizeof()を見ると、構造体のサイズではなく、その構造体へのポインターのサイズが返されていることがわかります。これは、32ビットプラットフォームの場合は4バイト、64ビットプラットフォームの場合は8バイトです。これは、構造体自体ではなく、POINTER TOASTRUCTをtypedefしたためです。sizeof(pStudentRecord)は4を返します。
したがって、構造自体に明らかな方法でスペースを割り当てることはできません。ただし、コンパイラはこの愚かさを考慮に入れています。pStudentRecordは、メモリを有効に割り当てるために使用できる名前/タイプではなく、匿名の「概念」構造へのポインタですが、そのサイズをコンパイラにフィードできます。
pStudnetRecord g_ppRecords [2]; pStudentRecord * record = malloc(sizeof(* g_ppRecords [1]));
より良い方法はこれを行うことです:
typedef struct { ... } StudentRecord; // Struct
typedef StudentRecord* pStudentRecord; // Pointer-to struct
これで、構造体StudentRecordと、pStudentRecordを使用したそれらへのポインターを明確な方法で作成できるようになりました。
強制的に使用する方法は非常に悪い習慣ですが、現時点では必ずしも問題ではありません。intsを使用した単純化された例に戻りましょう。
私の人生を複雑にするためにtypedefを作りたいが、ここで起こっている概念を説明したい場合はどうなりますか?古いintコードに戻りましょう。
typedef int* array_of_ints;
int *array1[4];
int **array2 = malloc(sizeof(int *) * 4); // Equivalent-ish to the line above
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
int a, b, c, d;
*array1[0] = &a; *array1[1] = &b; *array1[2] = &c; *array1[3] = &d;
*array2[0] = &a; *array2[1] = &b; *array2[2] = &c; *array2[3] = &d;
*array3[0] = &a; *array3[1] = &b; *array3[2] = &c; *array3[3] = &d;
ご覧のとおり、これはpStudentRecordで使用できます。
pStudentRecord array1[4];
pStudentRecord *array2 = malloc(sizeof(pStudentRecord) * 4);
すべてをまとめると、論理的に次のようになります。
array1[0]->firstName = "Christopher";
*array2[0]->firstName = "Christopher";
同等です。(注:上記のように正確に実行しないでください。実行時に文字列にchar *ポインターを割り当てることは、十分なスペースがすでに割り当てられていることがわかっている場合にのみ問題ありません)。
これは本当に最後の1ビットをもたらすだけです。私たちがmallocしたこのすべての記憶をどうしますか?どうすれば解放できますか?
free(array1);
free(array2);
そして、ポインター、匿名構造体のtypedef、およびその他のものに関する深夜のレッスンの終わりがあります。