为什么我在初始化结构时会遇到段错误?

搜索了一个小时左右。 我想我最好在这里发布这个问题。

我简化了代码。 segfault位于函数initMyStruct

 #include "stdlib.h" typedef struct { int * arr1; int * arr2; } myStruct; void allocMyStruct (myStruct * a, int num) { a = malloc(sizeof(myStruct)); a->arr1 = malloc(10*sizeof(int)); a->arr2 = malloc(10*num*sizeof(int)); } void initMyStruct (myStruct * a, int num) { int i; for (i = 0; i arr1[i] = 0; for (i = 0; i arr2[i] = -1; } void freeMyStruct (myStruct * a, int num) { int i; for (i = 0; i arr1); for (i = 0; i arr2); free(a); } int main (void) { int num = 3; myStruct * a; allocMyStruct (a, num); initMyStruct (a, num); freeMyStruct (a, num); return 1; } 

因为您没有保持指向新分配的内存的指针,而是使用未初始化的指针并获取未定义的行为。

您将a变量传递给allocMyStruct() ,但该调用(与所有其他调用一样) 按值 ,因此在函数内分配给它的新值不会影响main()的值。

更改它,以便allocMyStruct() 返回新的指针值,或者获取指针指针。 我更喜欢前者,它更干净,使用函数返回值通常会导致更好的代码:

 myStruct * allocMyStruct(int num) { myStruct *p; if((p = malloc(sizeof *p + 10 * sizeof *p->arr1 + 10 * num * sizeof *p->arr2)) != NULL) { p->arr1 = (int *) (p + 1); p->arr2 = p->arr1 + 10; } return p; } 

上面的代码还简化了内存分配,在一个大的malloc()调用中完成所有操作,然后将其“切片”为您实际需要的三个部分。

如果arr1的大小总是10,那么动态分配是没有意义的,它应该只是int arr1[10]; 在struct声明中。

a未使用,未更改为:

 myStruct * allocMyStruct (int num) { myStruct *a; a = malloc(sizeof(myStruct)); a->arr1 = malloc(10*sizeof(int)); a->arr2 = malloc(10*num*sizeof(int)); return a; } myStruct * a = allocMyStruct(num); 

此外,您无需循环自由function

 void freeMyStruct (myStruct * a, int num) { int i; for (i = 0; i < 10; i++) free(a->arr1); for (i = 0; i < 10*num; i++) free(a->arr2); free(a); } 

一定是

 void freeMyStruct (myStruct * a) { free(a->arr1); free(a->arr2); free(a); } 

当你调用void allocMyStruct (myStruct * a, int num)a指针将作为一个值传递,a参数是指针从main的本地副本,在你更改三个函数中的任何a函数后, main不会改变。

为此,您必须使用双指针作为函数参数,因此这些函数将获取指针的地址,以便它们可以修改它。

 #include "stdlib.h" typedef struct { int * arr1; int * arr2; } myStruct; void allocMyStruct (myStruct ** a, int num) { *a = malloc(sizeof(myStruct)); (*a)->arr1 = malloc(10*sizeof(int)); (*a)->arr2 = malloc(10*num*sizeof(int)); } void initMyStruct (myStruct ** a, int num) { int i; for (i = 0; i < 10; i++) (*a)->arr1[i] = 0; for (i = 0; i < 10*num; i++) (*a)->arr2[i] = -1; } void freeMyStruct (myStruct ** a, int num) { free((*a)->arr1); free((*a)->arr2); free(*a); *a = NULL; } int main (void) { int num = 3; myStruct * a; allocMyStruct (&a, num); initMyStruct (&a, num); freeMyStruct (&a, num); return 1; } 

编辑:Alter Mann是关于多次释放相同地址的权利,在Linux上你会立即崩溃双重释放。 他有一个更简单的解决方案。