我想我对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;
}
如果我取消注释coordinates[i] = coord_p;
,结果是数组的所有元素都有最后一个初始化的struct元素。因此,如果我打印每个坐标[i]-> x和坐标[i]-> y,它将说'4 4'5次。但是,当我使用直接struct元素副本时,如果我将其打印出来,则会得到正确的输出“ 0 0、1 1、2 2 ...”。
我希望不要为数组的各个元素分配内存,因为它们是在循环中初始化的。我也希望它coordinates[i] = coord_p;
应该复制指针值,让类似的东西printf("%d", coordinates[0]->x);
正常工作。但是,在两种情况下,我显然都误会了一些东西。
...为什么指向结构的指针数组需要为数组的各个元素调用malloc(),即使我认为如果要分别初始化它们,则应该为它们自动分配内存。
简单的答案是,从这个意义上讲,C永远不会为您“自动”分配任何东西。
考虑它的一种方法是C为您的命名变量分配足够的内存,仅此而已。如果你说
int i;
C为一个分配足够的内存int
。如果你说
double a[10];
C分配足够的内存10double
秒钟。如果你说
int *p;
C为一个指向int的指针分配了足够的内存,但它没有为该指针指向分配任何内存!
几乎毫无例外,在声明指针时,您有责任考虑指针将指向的内存的分配。C永远不会自动为您做到这一点。
在您的特定示例中,当您说
coord* coordinates[5];
C为5个指针分配了空间coord
-但为0个实际实例分配了空间coord
。另一方面,如果您说
coord coordinatesa[5];
C会为-的5个实际实例分配空间,coord
尽管显然不使用此数组,因为不涉及指针。
当您分配了5个指针,但没有的实际实例时coord
,如果您尝试使用其中一个指针,那将是一个严重的错误:
coord* coordinates[5];
coordinates[0]->x = 1; /* WRONG */
coordinates[0]->y = 2; /* WRONG */
解决此问题的一种方法是,首先确保coordinates[0]
指向某处:
coord* coordinates[5];
coordinates[0] = malloc(sizeof(coord));
coordinates[0]->x = 1; /* better */
coordinates[0]->y = 2; /* better */
其次,在填充指针数组时,似乎有必要分别复制结构的元素,而仅将指针复制到结构本身是行不通的。
嗯,但是当您复制指针时,您将进行源指针的分配,而失去了目标指针的分配。
以我前面的示例为例,如果要说的话,请混入程序的一部分
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;
这会“起作用”,但是很浪费,而且可能是错误的。malloc
调用分配的内存永远不会使用,当您说
coordinates[0] = coord_p;
旧的指针将被覆盖,指向的内存(malloc
恰好给您!)丢失了。
分配之后,由指向的内存分配就是分配的coordinates[0]
任何内容coord_p
,在这种情况下为单一coord
结构coordinate
。正如我所说,这乍看起来似乎“可行”,但是如果coordinate
局部变量超出范围,或者如果您最终将其重新用于coordinates
数组中的所有5个坐标,则将会遇到问题。
另一方面,如果您说
*coordinates[0] = *coord_p;
或者,等效地,
coordinates[0]->x = coord_p->x;
coordinates[0]->y = coord_p->y;
现在,您将从coord
指向的对象中获取数据coord_p
,并将其安全地复制到指向的内存中coordinates[0]
。完成此操作后,您(a)正确使用了分配给您的内存coordinates[0]
以指向,并且(b)使自己免受以后发生的任何事情所影响coord_p
。
但是,到目前为止,在这种情况下,我们根本不必使用中间coord_p
指针。我们也可以说
coord coordinate;
coordinate.x = 1;
coordinate.y = 2;
*coordinates[0] = coordinate;
或者,等效地,
coordinates[0]->x = coordinate.x;
coordinates[0]->y = coordinate.y;
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句