我必须使用以下代码块进行学校作业,严格禁止任何修改。
typedef struct { char* firstName; char* lastName; int id; float mark; }* pStudentRecord; pStudentRecord* g_ppRecords; int g_numRecords =0;
这里g_ppRecords应该是一个指向结构的指针数组。 我完全没有理解的是, pStudentRecords *g_ppRecords;
如何声明pStudentRecords *g_ppRecords;
意味着g_ppRecords
是一个数组,因为数组应该被定义为
type arrayname[size];
我尝试动态地为g_ppRecords分配内存,但这没有帮助。
g_ppRecords = (pStudentRecord*) malloc(sizeof(pStudentRecord*)*(g_numRecords+1));
观察到pStudentRecord
是pStudentRecord
作为指向结构的指针。 C中的指针简单地指向内存块的开始,无论该块是包含1个元素(正常的“标量”指针)还是10个元素(“数组”指针)。 因此,例如,以下内容
char c = 'x'; char *pc = &c;
使pc
指向一个以字符'x'
开头的内存,而以下内容
char *s = "abcd";
使s
指向以"abcd"
开头的内存(后面跟一个空字节)。 类型相同,但它们可能用于不同的目的。
因此,一旦分配,我可以通过执行例如g_ppRecords[1]->firstName
来访问g_ppRecords
的g_ppRecords[1]->firstName
。
现在,要分配这个数组:你想使用g_ppRecords = malloc(sizeof(pStudentRecord)*(g_numRecords+1));
(尽管注意sizeof(pStudentRecord*)
和sizeof(pStudentRecord)
是相等的,因为它们都是指针类型)。 这使得一个未初始化的结构指针数组。 对于数组中的每个结构指针,您需要通过分配新结构为其赋值。 问题的关键在于如何分配单一结构,即
g_ppRecords[1] = malloc(/* what goes here? */);
幸运的是,您实际上可以取消引用sizeof
指针:
g_ppRecords[1] = malloc(sizeof(*g_ppRecords[1]));
请注意, sizeof
是一个编译器构造。 即使g_ppRecords[1]
不是有效指针,该类型仍然有效,因此编译器将计算正确的大小。
编辑:更新了“BIG MISTAKE”部分。
关于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是相同的类型:指向类型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 *)。
在这里指出操作者优先是很重要的。 取消引用运算符[]优先于* 1。 所以绝对清楚,我们正在做的是:
*(array3[0]) = 4;
现在,让我们将主题更改为结构和typedef。
struct foo { int a; }; // Declares a struct named foo typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar'
你为什么要输入一个匿名结构? 好吧,为了便于阅读!
struct foo a; // Declares a variable a of type struct foo bar b; // Notice how you don't have to put 'struct' first
声明一个function……
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个字节。 这是因为我们为一个结构键入了一个POINTER,而不是一个结构本身。 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和其他东西的深夜课程结束了。
数组通常用指向其第一个元素的指针来引用。 如果你为10个学生记录提供足够的空间,然后在g_ppRecords中存储指向该空间开头的指针,g_ppRecords [9]将向前计数9个记录指针长度并取消引用那里的内容。 如果你已经正确管理了你的空间,那么arrays中的最后一条记录是什么,因为你预留了足够的空间来容纳10个。
简而言之,您已经分配了空间,如果它是正确的长度,您可以随心所欲地对待它,包括作为数组。
我不确定你为什么要为g_numRecords + 1记录分配空间。 除非g_numRecords被混淆地命名,否则你的数组中的空间将超过你需要的空间。
这里g_ppRecords应该是一个指向结构的指针数组。 我完全没有理解的是,声明怎么可能* pStudentRecords g_ppRecords; 意味着g_ppRecords是一个数组。 作为数组应定义为
type arrayname [size];
嗯type arrayname[size];
是在C中定义数组的许多方法的 一种方法 。
这静态地定义了一个数组,大多数值根据它的定义位置存储在堆栈中,数组的大小必须在编译时知道,尽管在某些现代编译器中可能不再是这种情况。
另一种方法是在运行时动态创建一个数组,所以我们不必知道编译时的大小,这是指针进来的地方,它们是存储动态分配的内存块地址的变量。
一个简单的例子就是这种type *array = malloc(sizeof(type) * number_of_items);
malloc返回一个存储在array
的内存地址,注意我们不会出于安全原因对返回类型进行类型转换。
回到手头的问题。
typedef struct { char* firstName; char* lastName; int id; float mark; }* pStudentRecord; pStudentRecord* g_ppRecords; int g_numRecords = 0;
这个typedef
有点不同于大多数注意}*
它基本上是指向结构的指针,所以这个:
pStudentRecord* g_ppRecords;
实际上是:
struct { char* firstName; char* lastName; int id; float mark; }** pStudentRecord;
它指向指针的指针,为什么他们会以这种方式定义typedef
,它超出我的范围,我个人不推荐它,为什么?
一个问题是我们怎么能通过它的免费精选名字大全得到结构的大小? 简单我们不能! 如果我们使用sizeof(pStudentRecord)
我们将获得4
或8
具体取决于底层架构,因为这是一个指针,在不知道结构大小的情况下我们无法使用其typedef名称真正动态分配它,那么我们能做些什么呢? ,声明第二个结构如下:
typedef struct { char* firstName; char* lastName; int id; float mark; } StudentRecord; g_ppRecords = malloc(sizeof(StudentRecord) * g_numRecords);
无论哪种方式,您确实需要联系原始创建此代码的人员或维护和提出您的问题的人员。
g_ppRecords=(pStudentRecord) malloc( (sizeof(char*) + sizeof(char*) + sizeof(int) + sizeof(float)) *(g_numRecords+1));
这似乎是一种可能的方式,遗憾的是, 没有结构的保证 ,所以它们实际上可以在成员之间包含填充,因此结构的总大小实际上可以大于其组合成员,更不用说地址可能不同。
编辑
显然,我们可以通过简单地推断它的类型来获得结构的大小
所以:
pStudentRecord g_ppRecords = malloc(sizeof(*g_ppRecords) * g_numRecords);
工作良好!
以上就是c/c++开发分享指向结构的动态数组指针相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/545642.html