Ugu*_*guu 2 c malloc struct pointers
我认为我对 C 中的内存和指针有一个根本性的误解。我想问为什么需要为数组的malloc()
各个元素调用指向结构的指针数组,即使我认为如果它们是单独初始化的,那么应自动为它们分配内存。其次,在填充指针数组时,似乎有必要单独复制结构体的元素,而简单地将指针复制到结构体本身是行不通的。
在其他程序中,我一直在使用结构体和指针,并且我一直必须找出实现它们的正确方法,所以我想直观地理解它,而不是仅仅接受单词“你只需要malloc()
单个元素”数组的”
/* suppose I have "typedef struct coord { int x; int y; } coord;" */
int num_rooms = 5;
coord* coordinates[num_rooms];
int i, j;
/* why is this required? in the following loop, coord[i] gets initialized,
and I thought memory automatically gets allocated on the stack because of
the initialization */
for (i = 0; i < num_rooms; i++) {
coordinates[i] = (coord*) malloc(sizeof(coord));
}
/* fill the array of coord pointers */
for (j = 0; j < num_rooms; j++) {
coord coordinate;
coord *coord_p;
coord_p = &coordinate;
coord_p->x = j;
coord_p->y = j;
/* this does not work. It just makes all array elements have the same struct elements. (the second question) Why does it require copying over individual field elements instead of copying the pointer?*/
//coordinates[j] = coord_p;
/* however, assigning individual elements doesn't cause segmentation fault */
coordinates[j]->x = coord_p->x;
coordinates[j]->y = coord_p->y;
}
Run Code Online (Sandbox Code Playgroud)
如果我取消注释coordinates[i] = coord_p;
,最终数组的所有元素都具有最后一个初始化元素的结构元素。因此,如果我打印每个坐标[i]->x和坐标[i]->y,它会说“4 4”5次。但是当我使用直接结构元素复制时,如果打印它,我会得到正确的输出“0 0, 1 1, 2 2, ...”。
我希望不为数组的各个元素分配内存应该没问题,因为它们是在循环中初始化的。我还希望coordinates[i] = coord_p;
应该复制指针值,让类似的东西printf("%d", coordinates[0]->x);
正常工作。然而,在这两种情况下我显然都误解了一些东西。
...为什么指向结构的指针数组需要为数组的各个元素调用 malloc() ,即使我认为如果它们单独初始化,那么应该自动为它们分配内存。
简单的答案是,从这个意义上说,C 永远不会“自动”为您分配任何东西。
一种思考方式是,C 为命名变量分配了足够的内存,仅此而已。如果你说
int i;
Run Code Online (Sandbox Code Playgroud)
C 为 1 分配足够的内存int
。如果你说
double a[10];
Run Code Online (Sandbox Code Playgroud)
C分配了足够10double
秒的内存。如果你说
int *p;
Run Code Online (Sandbox Code Playgroud)
C 为一个指向 int 的指针分配了足够的内存,但它没有为该指针分配任何内存!
几乎无一例外,当您声明指针时,您有责任考虑指针将指向的内存的分配。C 永远不会自动为你做这件事。
在你的具体例子中,当你说
coord* coordinates[5];
Run Code Online (Sandbox Code Playgroud)
C 为 5 个指针分配了空间coord
- 但它为 0 个实际实例分配了空间coord
。另一方面,如果你说
coord coordinatesa[5];
Run Code Online (Sandbox Code Playgroud)
C 会为 5 个实际实例分配空间coord
- 尽管您显然会以完全不同的方式使用该数组,因为不涉及指针。
当您分配了 5 个指针,但没有 的实际实例时coord
,如果您尝试使用其中一个指针,那将是一个严重的错误:
coord* coordinates[5];
coordinates[0]->x = 1; /* WRONG */
coordinates[0]->y = 2; /* WRONG */
Run Code Online (Sandbox Code Playgroud)
解决此问题的一种方法是首先确保该coordinates[0]
点位于某处:
coord* coordinates[5];
coordinates[0] = malloc(sizeof(coord));
coordinates[0]->x = 1; /* better */
coordinates[0]->y = 2; /* better */
Run Code Online (Sandbox Code Playgroud)
其次,在填充指针数组时,似乎有必要单独复制结构体的元素,而简单地将指针复制到结构体本身是行不通的。
啊,但是当您复制指针时,您会携带源指针的分配,并丢失目标指针的分配。
以我前面的例子为例,并混合到你的程序的一部分中,如果你想说
coord* coordinates[5];
coordinates[0] = malloc(sizeof(coord));
coord coordinate;
coord *coord_p;
coord_p = &coordinate;
coord_p->x = 1;
coord_p->y = 2;
coordinates[0] = coord_p;
Run Code Online (Sandbox Code Playgroud)
这会“起作用”,但这是浪费而且可能是错误的。调用分配的内存malloc
永远不会被使用,当你说
coordinates[0] = coord_p;
Run Code Online (Sandbox Code Playgroud)
旧指针被覆盖,指向的内存(malloc
非常好心地给了你!)丢失了。
在这次分配之后,所指向的内存分配coordinates[0]
就是任何coord_p
分配,在本例中是单个coord
结构coordinate
。正如我所说,一开始这似乎“有效”,但如果它coordinate
是一个超出范围的局部变量,或者如果您最终将它重新用于数组中的所有 5 个坐标coordinates
,那么您将会遇到问题。
另一方面,如果你说
*coordinates[0] = *coord_p;
Run Code Online (Sandbox Code Playgroud)
或者,等价地,
coordinates[0]->x = coord_p->x;
coordinates[0]->y = coord_p->y;
Run Code Online (Sandbox Code Playgroud)
coord
现在您正在从指向的数据中获取数据coord_p
,并将其安全地复制到 指向的内存中coordinates[0]
。完成此操作后,您(a)正确使用了分配给 指向的内存coordinates[0]
,并且(b)使自己免受稍后发生的 指向的内存的影响coord_p
。
但到目前为止,在这种情况下,我们coord_p
根本不必使用中间指针。我们也可以说
coord coordinate;
coordinate.x = 1;
coordinate.y = 2;
*coordinates[0] = coordinate;
Run Code Online (Sandbox Code Playgroud)
或者,等价地,
coordinates[0]->x = coordinate.x;
coordinates[0]->y = coordinate.y;
Run Code Online (Sandbox Code Playgroud)