编辑:更新了“大错误”部分。
关于 C 风格(不同于 C++!)类型定义的快速课程,以及它为何如此,以及如何使用它。
首先,一个基本的 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 是相同的类型:指向类型 int 的指针,即使您没有在 ip1 的声明中添加 *。那个 * 是在声明中。
切换话题。您谈到将数组声明为
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 **。这意味着指向 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
看看最后一个声明中只有一个 * 吗?那是因为其中一个是“在 typedef 中”。使用最后一个声明,您现在拥有一个大小为 4 的数组,其中包含 4 个指向 int (int *) 的指针。
在这里指出操作员优先级很重要。取消引用运算符 [] 优先于 * 之一。所以要绝对清楚,我们正在做的是:
*(array3[0]) = 4;
现在,让我们将主题更改为结构和类型定义。
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);
看看我们如何不必将 'struct' 放在 arg2 前面?
现在,我们看到您必须使用的代码以这种方式定义了一个结构:
typedef struct { } * foo_pointers;
这类似于我们之前如何处理指针数组:
typedef int* array_of_ints;
并排比较
typedef struct { } * foo_pointers;
typedef int* array_of_ints;
唯一的区别是一个是 struct {},另一个是 int。
使用我们的 foo_pointers,我们可以声明一个指向 foo 的指针数组,如下所示:
foo_pointers fooptrs[4];
现在我们有一个数组,其中存储了 4 个指向我们无法访问的匿名结构的指针。
话题切换!
不幸的是,你的老师犯了一个错误。如果查看上面 foo_pointers 类型的 sizeof(),会发现它返回的是指向该结构的指针的大小,而不是结构的大小。这是 32 位平台的 4 个字节或 64 位平台的 8 个字节。这是因为我们定义了一个指向结构的指针,而不是结构本身。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
我们现在能够以清晰的方式创建 struct StudentRecord 以及使用 pStudentRecord 指向它们的指针。
尽管您被迫使用的方法是非常糟糕的做法,但目前这并不是一个问题。让我们回到使用整数的简化示例。
如果我想成为一个 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* 指针分配给字符串只有在您知道已经分配了足够的空间时才可以)。
这只真正带来了最后一点。我们如何处理我们 malloc 的所有这些内存?我们如何释放它?
free(array1);
free(array2);
关于指针、匿名结构的 typedef 和其他内容的深夜课程结束了。