1

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

我简化了代码。段错误在函数中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 < 10; i++)     a->arr1[i]  =  0;
        for (i = 0; i < 10*num; i++) a->arr2[i]  = -1;
}
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);
}
int main (void) {
        int num = 3;
        myStruct * a;
        allocMyStruct (a, num);
        initMyStruct  (a, num);
        freeMyStruct  (a, num);
        return 1;
}
4

3 回答 3

5

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

您将a变量传递给 in allocMyStruct(),但该调用(与所有其他调用一样)是按 value进行的,因此在函数内部分配给它的新值不会影响ain的值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 声明中。

于 2013-11-04T10:28:59.943 回答
2

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);

此外,无需循环您的免费功能

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);
}
于 2013-11-04T10:30:33.700 回答
1

当您调用指针时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 上,双重释放会立即崩溃。他有一个更简单的解决方案。

于 2013-11-04T10:30:56.690 回答