如何释放结构中的动态二维数组?

时间:2014-01-22 05:05:48

标签: c arrays struct malloc free

我在这个结构中有一个动态的二维数组:

struct mystruct{
    int mySize;
    int **networkRep;
};

在我的代码块中,我按如下方式使用它:

struct myStruct astruct[100];
astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);
// do stuff...
int i;
for(i=0; i<100; i++)
    freeMatrix(astruct[i].networkRep, 200);

这是我声明2d数组的方式:

int** declareMatrix(int **mymatrix, int rows, int columns)
{
    mymatrix = (int**) malloc(rows*sizeof(int*));
    if (mymatrix==NULL)
        printf("Error allocating memory!\n");
    int i,j;
    for (i = 0; i < rows; i++)
        mymatrix[i] = (int*) malloc(columns*sizeof(int));

    for(i=0; i<rows; i++){
        for(j=0; j<columns; j++){
            mymatrix[i][j] = 0;
        }
    }
    return mymatrix;
}

这就是我释放二维数组的方式:

void freeMatrix(int **matrix, int rows)
{
    int i;
    for (i = 0; i < rows; i++){
        free(matrix[i]);
    }
    free(matrix);
    matrix = NULL;
}

我所看到的奇怪的行为是,当我编译并运行我的程序时,一切看起来都不错。但是当我将stdout传输到txt文件时,我遇到了一个seg错误。但是,如果我注释掉包含&#34; freeMatrix&#34;的循环,则不会发生seg错误。呼叫。我做错了什么?

4 个答案:

答案 0 :(得分:1)

我发现免费代码没有任何问题,除了freeMatrix被调用100次,而您的分配只是1

所以,你要么分配如下:

 for(int i=0; i<100; i++) //Notice looping over 100 elements. 
    astruct[i].networkRep = declareMatrix(astruct[i].networkRep, 200, 200);

或者,只为您在原始代码中分配的第0个元素免费。

freeMatrix(astruct[0].networkRep, 200);

旁注:初始化astruct array

mystruct astruct[100] = {};

答案 1 :(得分:1)

struct myStruct astruct[100];

astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);

// do stuff...
int i;
for(i=0; i<100; i++)
    freeMatrix(astruct[i].networkRep, 200);

你分配了一个astruct,但释放了100个;如果任何99个额外的不是NULL,那么会崩溃,这可能在你进行重定向时发生。 (由于astruct在堆栈中,它将包含留在那里的任何内容。)

其他问题:

您使用的是数字文字而不是显式常量...定义NUMROWS和NUMCOLS并一致地使用它们。

摆脱declareMatrix的第一个参数......你传递一个值但从不使用它。

在freeMatrix中,

matrix = NULL;

什么都不做。启用优化后,编译器甚至不会生成任何代码。

if (mymatrix==NULL)
    printf("Error allocating memory!\n");

您应该在出错时退出(1),否则您的程序将崩溃,您甚至可能看不到错误消息,因为a)stdout被缓冲并且b)您将其重定向到文件。这也是将错误消息写入stderr而不是stdout的原因。

答案 2 :(得分:0)

astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200); 

你没有传递指针的地址。它只是将内存中的值传递给不需要的函数。

你唯一初始化struct的第一个变量,但是当你试图释放内存时,你正在分配尚未分配的内存(astruct [1],依此类推,直到100)。

当您使用malloc时,它实际上分配的内存比您指定的多一点。额外内存用于存储诸如块大小之类的信息,以及指向下一个空闲/已使用块的链接,有时还包含一些保护数据,这有助于系统检测您是否写过了结束分配块。

如果传入不同的地址,它将访问包含垃圾的内存,因此其行为未定义(但最常见的是导致崩溃)

答案 3 :(得分:0)

索引和计数无符号整数类型就足够了。 size_t是这种类型的选择,因为它保证足够大以处理/索引目标机器上内存/数组元素的每个字节。

struct mystruct
{
  size_t mySize;
  int ** networkRep;
};

始终正确初始化变量:

struct myStruct astruct[100] = {0};

分配器的几个问题:

可以这样做:

int declareMatrix(int *** pmymatrix, size_t rows, size_t columns)
{
    int result = 0; /* Be optimistc. */

    assert(NULL != pmatrix);

    *pmymatrix = malloc(rows * sizeof(**pmymatrix));
    if (NULL == *pmymatrix)
    {
      perror("malloc() failed");
      result = -1;

      goto lblExit;
    }

    { 
      size_t i, j;
      for (i = 0; i < rows; i++)
      {
        (*pmymatrix)[i] = malloc(columns * sizeof(***pmymatrix));
        if (NULL ==   (*pmymatrix)[i])
        {
          perror("malloc() failed");
          freeMatrix(pmymatrix); /* Clean up. */
          result = -1;

          goto lblExit;
        }

        for(i = 0; i < rows; ++i)
        {
          for(j = 0; j < columns; ++j)
          {
            (*pmymatrix)[i][j] = 0;
          }
        }
      }
    }

lblExit:
    return 0;
}

解除分配器的两个问题:

  • 标记它的工作就像正确地取消启动指针一样。
  • 在对其进行操作之前执行输入验证。

可以这样做:

void freeMatrix(int *** pmatrix, size_t rows)
{
  if (NULL != pmatrix)
  {
    if (NULL != *pmatrix)
    {
      size_t i;
      for (i = 0; i < rows; ++i)
      {
        free((*pmatrix)[i]);
      }
    }

    free(*pmatrix);
    *pmatrix = NULL;
  }
}

然后使用这样的东西:

struct myStruct astruct[100] = {0};

...

int result = declareMatrix(&astruct[0].networkRep, 200, 200);
if (0 != result)
{
  fprintf("declareMatrix() failed.\n");
}
else
{
// Note: Arriving here has only the 1st element of astruct initialised! */
// do stuff...
}

{
  size_t i;
  for(i = 0; i < 100; ++i)
  {
    freeMatrix(&astruct[i].networkRep, 200);
  }
}