我正在做一个C程序(Linux, GCC)与三层结构:
typedef struct innerThing{
int data;
} inner;
typedef struct middleThing{
size_t elements;
inner collection[];
} middle;
typedef struct outerThing{
size_t outerElements;
size_t totalElements;
middle collection[];
} outer;
使用这个网站上的其他帖子,我拼凑了应该构建这些结构的2D系统的代码。当我使用malloc()方法获取所需的空间,然后遍历它时,一切看起来都很好:
int main(){
outer* outerThing = (outer*)malloc(sizeof(outer) + (4*sizeof(middle)) * (6*sizeof(inner)) );
outerThing->totalElements = 4 * 6;
outerThing->outerElements = 4;
int i, j;
middle* ptr1;
inner* ptr2;
// Have to manually set the "elements" metadata for middle structs
for(i=0, ptr1 = outerThing->collection; i<outerThing->outerElements; ptr1=ptr1+1, i++){
ptr1->elements = 6;
}
for(i=0, ptr1=outerThing->collection; i<outerThing->outerElements; ptr1=ptr1+1, i++){
for(j=0, ptr2=ptr1->collection; j<ptr1->elements; ptr2=ptr2+1, j++){
printf(".");
}
printf("n");
}
free(outerThing);
return 0;
}
输出是:
[Linux]$ gcc -Wall threeStructs.c
[Linux]$ ./a.out
......
......
......
......
[Linux]$
非常鼓励…虽然我原以为是四列,每列六颗星。也许这是第一个问题。然而,让我抓狂的是,当我修改嵌套循环以插入数据时:
for(i=0, ptr1=outerThing->collection; i<outerThing->outerElements; ptr1=ptr1+1, i++){
for(j=0, ptr2=ptr1->collection; j<ptr1->elements; ptr2=ptr2+1, j++){
printf(".");
ptr2->data=0; // <<< Added
}
printf("n");
}
现在程序的行为改变了。当我重新运行它时,我看到如下:
[Linux]$ gcc -Wall threeStructs.c
[Linux]$ ./a.out
......
[Linux]$
我已经用GDB完成了这一步,我注意到第一个内部循环运行得很好。然而,剩余的内部循环永远不会运行,因为ptr1->elements
以某种方式从6覆盖到0。当我将ptr2->data
线设置为9或7或I +j时,程序段故障;
ptr1->elements
从0覆盖到12898794682。我确信当我在内部结构中设置数据时,它以某种方式覆盖了中间结构中的数据。如果我必须大胆猜测,这是因为我的malloc()调用太原始了吗?我应该malloc()外部结构,然后中间结构,然后循环内部结构吗?如果是这样,在循环中执行malloc()是否有任何危险?我认为这是C编程的禁忌。
谢谢!皮特
我无法让这个工作。我只需要两层结构体就可以让它工作,但不需要三层。
然而,我想到我只有一个外部结构体。所以我用一个数组代替了它,在main()
中声明。语义有点奇怪,但这个解决方案是有效的。下面是代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define NUM_SETS 10
#define NUM_LINES 20
typedef struct innerStruct {
int data;
} inner;
typedef struct middleStruct {
size_t elements;
inner collection[];
} middle;
int main(){
middle* arr[NUM_SETS];
inner* ptr;
int i, j;
// set up the array
for(i=0; i<NUM_SETS; i++){
arr[i] = (middle*)malloc(sizeof(middle) + (NUM_LINES * sizeof(inner)) );
arr[i]->elements = NUM_LINES;
}
// Test populate the array
for(i=0; i<NUM_SETS; i++){
for(j=0, ptr=arr[i]->collection; j<NUM_LINES; j++, ptr=ptr+1){
ptr->data=i+j; // or whatever
}
}
// free everything
for(i=0; i<NUM_SETS; i++){
free(arr[i]);
}
return 0;
}