user-0 提问: 柔性数组中free的问题

回复:
user: user-0
content: 引用 1 楼 akari10032 的回复:staff结构体定义里面info前面的*去掉试试， 这样应该是不行，当然我也试了下  void staff_free(staff **worker) {     int Len = (*worker)->num;     //free((*worker)->infor);     for (int i = 0; i < Len; i++)     {         printf("loop: the %d staff addr is %p\n", i, &((*worker)->infor[i]));         free(&((*worker)->infor[i]));     }     free(*worker); }  把改成数组，地址要不以首元素表示free((*worker)->infor);，要不这样free(&((*worker)->infor[i])); 以首元素作为地址应该不行，因为柔性数组，系统不知道我申请了多少。 以第二种方式表示，我试过了。结果如图  其实我觉得错误是我对free没搞明白，虽然是free掉malloc申请的空间。但一般都是对指针指向的free，我没见过直接free空间地址的，我不知道这样可以不，感觉应该没问题，可好像是这样才会段错误的。

user: user-1
content: staff结构体定义里面info前面的*去掉试试，

user: user-0
content: 引用 7 楼 user-2 的回复:你那样不是指针数组，而是数组指针，不能用数组指针的，因为数组指针需要数组的长度固定 char (*)c[5]; c++;指针会移动 sizeof(char)*5 个字节的地址，如果是柔性数组[]，c++就不知道该移动多少个字节了 正如你所说，你不用指针，用数组就好了 typedef struct _staff {     int num;     info infor[]; //柔性数组 } staff;  (*worker)->infor[1].age = 5;  谢谢

user: user-2
content: 你那样不是指针数组，而是数组指针，不能用数组指针的，因为数组指针需要数组的长度固定 char (*)c[5]; c++;指针会移动 sizeof(char)*5 个字节的地址，如果是柔性数组[]，c++就不知道该移动多少个字节了 正如你所说，你不用指针，用数组就好了 typedef struct _staff {     int num;     info infor[]; //柔性数组 } staff;  (*worker)->infor[1].age = 5;

user: user-0
content: 引用 5 楼 user-2 的回复:解释太费劲，你自己好好体会以下代码，好好看注释，看看正确做法和你的非正确做法的区别  struct Empty {     int num;     int *a[]; }; int main(int argc, const char * argv[]) {     int n = 5;     printf("正确做法：\n");     Empty *e = (Empty*)malloc(sizeof(Empty) + sizeof(int*)*n); //注意这里用int*     e->num = n;     for (int i=0; i<e->num; i++) {         e->a[i] = (int*)malloc(sizeof(int)); //申请的内存属于a[i]，所以这个释放a[i]         *e->a[i] = i+1; //能正常赋值         printf("%p, %d\n", e->a[i], *e->a[i]); //注意看这里的内存地址，这里能正常访问*a[i]     }     for (int i=0; i<e->num; i++) {         free(e->a[i]); //因为a[i]申请过内存，所以可以释放内存     }     free(e); //释放内存          printf("非正确做法：\n"); //这就是你的做法     e = (Empty*)malloc(sizeof(Empty) + sizeof(int)*n); //这里用int来申请内存，内存空间比int*大，数组访问没问题m，但a[i]都是野指针     e->num = 5;     for (int i=0; i<e->num; i++) {         //*e->a[i] = i+1; //a[i]是野指针，看看这里赋值是否正常？         //printf("%p, %d\n", e->a[i], *e->a[i]); //注意看这里的内存地址，这里是否能正常访问*a[i]？         printf("%p\n", e->a[i]); //能正常打印地址又如何，还不是野指针一个？     }     for (int i=0; i<e->num; i++) {         //free(e->a[i]); //这里没给a[i]申请过内存，所以不能给a[i]释放内存，也就是不能释放野指针     }     free(e); //申请的内存属于e，所以只能释放e     return 0; } 哦哦，多谢，我其实看到你前面说的就之前已经改成你的这个样子。只是一直没想明白是野指针。  *worker = (staff *)malloc(sizeof(staff) + num * sizeof(info)); 过去是我原来没想明白，柔性数组申请的空间是不是worker指向的，看了你的解释，我可以不写成指针，就写数组，然后free(worker)就行了。 最后一个问题哈，柔性数组是不是不能写指针数组。 typedef struct _staff {     int num;     info (*infor)[]; } staff; 我下面比如这样赋值(*worker)->infor[1]->age = 5;编译器就会告诉我"表达式必须指向完整类型的指针"。我如果不是柔性数组，这样写是没问题的，所以是我写法有问题，还是不支持此种格式？ 但是指针也是数据格式一种，我想应该支持吧？

user: user-2
content: 解释太费劲，你自己好好体会以下代码，好好看注释，看看正确做法和你的非正确做法的区别  struct Empty {     int num;     int *a[]; }; int main(int argc, const char * argv[]) {     int n = 5;     printf("正确做法：\n");     Empty *e = (Empty*)malloc(sizeof(Empty) + sizeof(int*)*n); //注意这里用int*     e->num = n;     for (int i=0; i<e->num; i++) {         e->a[i] = (int*)malloc(sizeof(int)); //申请的内存属于a[i]，所以这个释放a[i]         *e->a[i] = i+1; //能正常赋值         printf("%p, %d\n", e->a[i], *e->a[i]); //注意看这里的内存地址，这里能正常访问*a[i]     }     for (int i=0; i<e->num; i++) {         free(e->a[i]); //因为a[i]申请过内存，所以可以释放内存     }     free(e); //释放内存          printf("非正确做法：\n"); //这就是你的做法     e = (Empty*)malloc(sizeof(Empty) + sizeof(int)*n); //这里用int来申请内存，内存空间比int*大，数组访问没问题m，但a[i]都是野指针     e->num = 5;     for (int i=0; i<e->num; i++) {         //*e->a[i] = i+1; //a[i]是野指针，看看这里赋值是否正常？         //printf("%p, %d\n", e->a[i], *e->a[i]); //注意看这里的内存地址，这里是否能正常访问*a[i]？         printf("%p\n", e->a[i]); //能正常打印地址又如何，还不是野指针一个？     }     for (int i=0; i<e->num; i++) {         //free(e->a[i]); //这里没给a[i]申请过内存，所以不能给a[i]释放内存，也就是不能释放野指针     }     free(e); //申请的内存属于e，所以只能释放e     return 0; }

user: user-0
content: 引用 3 楼 user-2 的回复:free((*worker)->infor[i]); 没问题，问题是你每它分配过内存 你要先分配内存再释放 比如 (*worker)->num = num; printf("worker addr is %p\n", *worker); for (int i = 0; i < num; i++)     //printf("the %d staff addr is %p\n", i, &((*worker)->infor[i]));     (*worker)->infor[i] = (info*)malloc(sizeof(info)); //先申请内存，再释放 不是吧，我*worker = (staff *)malloc(sizeof(staff) + num * sizeof(info));这一开始申请了空间。 我想我知道是咋回事了，我在staff_free函数里又打印了一下，  void staff_free(staff **worker) {     int Len = (*worker)->num;     for (int i = 0; i < Len; i++)     {         printf("loop: the %d staff addr is %p, adr is %p\n", i, &((*worker)->infor[i]), (*worker)->infor[i]);         printf("The free %d worker's info is: age = %d, name = %s\n", i, (*worker)->infor[i]->age, (*worker)->infor[i]->name);         //free((*worker)->infor[i]);     }     free(*worker); }   show loop: the 0 staff addr is 0x887018, adr is 0x7ffe9421d4e0 The 0 worker's info is: age = 10, name = ZhangSan show loop: the 1 staff addr is 0x887020, adr is 0x7ffe9421d4e0 The 1 worker's info is: age = 10, name = ZhangSan show loop: the 2 staff addr is 0x887028, adr is 0x7ffe9421d4e0 The 2 worker's info is: age = 10, name = ZhangSan show loop: the 3 staff addr is 0x887030, adr is 0x7ffe9421d4e0 The 3 worker's info is: age = 10, name = ZhangSan show loop: the 4 staff addr is 0x887038, adr is 0x7ffe9421d4e0 The 4 worker's info is: age = 10, name = ZhangSan show loop: the 5 staff addr is 0x887040, adr is 0x7ffe9421d4e0 The 5 worker's info is: age = 10, name = ZhangSan show loop: the 6 staff addr is 0x887048, adr is 0x7ffe9421d4e0 The 6 worker's info is: age = 10, name = ZhangSan show loop: the 7 staff addr is 0x887050, adr is 0x7ffe9421d4e0 The 7 worker's info is: age = 10, name = ZhangSan show loop: the 8 staff addr is 0x887058, adr is 0x7ffe9421d4e0 The 8 worker's info is: age = 10, name = ZhangSan show loop: the 9 staff addr is 0x887060, adr is 0x7ffe9421d4e0 The 9 worker's info is: age = 10, name = ZhangSan  age应该是1到10的， 结果却是age全为10，有两种可能： 1. 后面的把前面的覆盖了 2. 都指向了最后的一个空间 我感觉第二种可能是对的，因为我free时候，i=0是可以free的，因为这个age是10，是申请过的。后面的没申请，所以不能free。 所以我觉得我打印的两个addr我理解的有问题，我之前理解的第一个&((*worker)->infor[i])应该是那个数组i的空间地址，(*worker)->infor[i]是指针的地址。 但如果是这样，就指向没出问题。我理解的哪里有问题？

user: user-2
content: free((*worker)->infor[i]); 没问题，问题是你每它分配过内存 你要先分配内存再释放 比如 (*worker)->num = num; printf("worker addr is %p\n", *worker); for (int i = 0; i < num; i++)     //printf("the %d staff addr is %p\n", i, &((*worker)->infor[i]));     (*worker)->infor[i] = (info*)malloc(sizeof(info)); //先申请内存，再释放