编辑:更新了“大错误”部分。
关于C语言(不同于C++!)typedef的快速教程,以及它为什么是这样,如何使用它。
首先,一个基本的typedef技巧。
typedef int* int_pointer;
int_pointer ip1;
int *ip2;
int a;
ip1 = &a;
ip2 = &a;
*ip1 = 4;
*ip2 = 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;
*array1[0] = 4;
让我们动态地分配那个数组。
int **array2 = malloc(sizeof(int *) * 4);
array2[0] = &a; // [] implicitly dereferences
*array2[0] = 4; // Sets a to 4
注意 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 *)的指针组成。
这里需要指出运算符优先级。解引用操作符[]优先于*操作符。所以为了绝对清楚,我们正在做以下操作:
*(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);
看到了吗,我们不需要在arg2前面加上“struct”?
现在,我们需要使用以下方式定义结构体的代码:
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个字节。这是因为我们typedef了一个指向结构体的指针,而不是结构体本身。sizeof(pStudentRecord)将返回4。
因此,你不能以明显的方式为结构体本身分配空间!然而,编译器允许这种愚蠢的行为。pStudentRecord不是您可以用来有效分配内存的名称/类型,它是一个指向匿名"概念性"结构体的指针,但我们可以将其大小提供给编译器。
pStudnetRecord g_ppRecords[2];
pStudentRecord *record = malloc(sizeof(*g_ppRecords[1]));
更好的做法是这样做:
typedef struct { ... } StudentRecord;
typedef StudentRecord* pStudentRecord;
我们现在可以清晰地制作struct StudentRecord,以及指向它们的pStudentRecord指针。
虽然强制使用的方法非常糟糕,但目前不是问题。让我们回到使用int的简化示例。
如果我想要创建一个typedef来使我的生活更加复杂,但解释这里发生的概念呢?让我们回到旧的int代码。
typedef int* array_of_ints;
int *array1[4];
int **array2 = malloc(sizeof(int *) * 4);
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以及其他相关内容的学习结束了。