【问题标题】:How to free dynamic 2d array that's in a struct?如何释放结构中的动态二维数组?
【发布时间】:2014-01-22 05:05:47
【问题描述】:

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

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

这就是我声明二维数组的方式:

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

我看到的奇怪行为是,当我编译并运行我的程序时,一切看起来都正常。但是当我将标准输出通过管道传输到 txt 文件时,我遇到了段错误。但是,如果我注释掉包含“freeMatrix”调用的循环,则不会发生段错误。我做错了什么?

【问题讨论】:

    标签: c arrays struct malloc free


    【解决方案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);
    

    旁注:初始化你的astructarray

    mystruct astruct[100] = {};
    

    【讨论】:

      【解决方案2】:
      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) 您将其重定向到文件。这也是将错误消息写入标准错误而不是标准输出的原因。

      【讨论】:

      • 谢谢。我认为这几乎就是问题所在。我释放的比分配的多,但在我的真实代码中并不像在我在这里放置的示例代码中那么明显。去掉declareMatrix的第一个参数是什么意思?该函数如何知道分配的内存应该指向哪里?
      • @theGman declareMatrix 的第一行设置 mymatrix;因此从不使用传入的值(并且该值未定义)。您返回 mymatrix 并将 astruct[0].networkRep 设置为等于它。不需要第一个参数。考虑一下 declareMatrix 就像 malloc ... 它不接受指针参数,它只返回一个指针值。
      • @theGman 另一种实现是将指针传递给指针并通过间接设置指针...有关此方法的示例,请参见 alk 的答案。
      【解决方案3】:
      astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200); 
      

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

      并且您唯一初始化 struct 的第一个变量,但是当您尝试释放内存时,您正在取消分配尚未分配的内存(astruct[1] 等等,直到 100 )。

      当您使用 malloc 时,它实际上分配的内存比您指定的要多。额外的内存用于存储信息,例如块的大小,以及指向下一个空闲/已用块的链接,有时还有一些 保护数据,可帮助系统检测您是否写到了末尾分配块。

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

      【讨论】:

      • 按照 OP 的代码调用 declareMatrix() 完全没问题。
      • OP 的 ??我只是说发送 astruct[0].networkRep 中包含的值是没有意义的,因为他一进入函数就将新地址分配给变量 mymatrix 并发送新地址。
      • 啊,我明白你现在的意思了,我同意。对不起,我误会了你。 (OP ==“原始发布”或“原始海报”)
      • 谢谢。我稍后会在代码中初始化更多的结构数组,所以它不仅仅是 astruct[0].networkRep 被声明。你能解释一下我应该如何将我的数组传递给declareMatrix吗?我以为指针正在被传递,内存被分配给它,然后返回。它似乎在我使用它的其他任何地方都有效......
      • @theGman 你的想法是完全错误的。您将未初始化的值传递给 mymatrix 参数。然后,您立即用 malloc 的结果覆盖它,并最终返回它,并将指针设置为它。该参数是不必要且无用的。如果您不理解这一点,请继续查看并跟踪发生的情况。如果您仍然不明白,那么您对函数参数的工作原理有一些基本的误解。要通过参数设置指针,您必须传递指针的地址,并间接存储(即存储到*pointertopointer)。
      【解决方案4】:

      对无符号整数类型进行索引和计数就足够了。 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);
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-01
        • 1970-01-01
        • 2021-04-21
        相关资源
        最近更新 更多