简体   繁体   English

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

[英]How to free dynamic 2d array that's in a struct?

I have a dynamic 2d array inside this struct: 我在这个结构中有一个动态的2d数组:

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

In my code block I use it as follows: 在我的代码块中,我使用它如下:

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

This is how I declare the 2d array: 这就是我声明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;
}

And this is how I free the 2d array: 这就是我释放2d数组的方式:

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

The strange behvior that I'm seeing is that when I compile and run my program everything looks OK. 我所看到的奇怪的行为是,当我编译并运行我的程序时,一切看起来都不错。 But when I pipe the stdout to a txt file, I'm getting a seg fault. 但是当我将stdout传输到txt文件时,我遇到了一个seg错误。 However, the seg fault doesn't occur if I comment out the loop containing the "freeMatrix" call. 但是,如果我注释掉包含“freeMatrix”调用的循环,则不会发生seg错误。 What am I doing wrong? 我究竟做错了什么?

I don't see any problem in free code, except, freeMatrix get called for 100 times whereas your allocation is just 1 . 我没有在免费代码中看到任何问题,除了, freeMatrix被调用100次,而你的分配只有1

So, either you allocate as below: 所以,要么分配如下:

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

Or, free for only 0th element which you have allocated in your original code. 或者,只为您在原始代码中分配的第0个元素免费。

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

On sidenote: Initialize your astruct array . 旁注:初始化您的astruct array

mystruct astruct[100] = {};
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);

You allocated one astruct but free 100 of them; 你分配了一个astruct但是释放了100个; that will crash if any of the 99 extra ones isn't NULL, which probably happens when you do your redirection. 如果任何99个额外的不是NULL,那么会崩溃,这可能在你进行重定向时发生。 (Since astruct is on the stack, it will contain whatever was left there.) (由于astruct在堆栈中,它将包含那里留下的任何内容。)

Other issues: 其他事宜:

You're using numeric literals rather than manifest constants ... define NUMROWS and NUMCOLS and use them consistently. 您使用的是数字文字而不是清单常量...定义NUMROWS和NUMCOLS并一致地使用它们。

Get rid of the first parameter to declareMatrix ... you pass a value but never use it. 摆脱declareMatrix的第一个参数...你传递一个值但从不使用它。

In freeMatrix, 在freeMatrix中,

matrix = NULL;

does nothing. 什么也没做。 With optimization turned on, the compiler won't even generate any code. 启用优化后,编译器甚至不会生成任何代码。

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

You should exit(1) upon error, otherwise your program will crash and you may not even see the error message because a) stdout is buffered and b) you're redirecting it to a file. 您应该在出错时退出(1),否则您的程序将崩溃,您甚至可能看不到错误消息,因为a)stdout被缓冲并且b)您将其重定向到文件。 Which is also a reason to write error messages to stderr, not stdout. 这也是将错误消息写入stderr而不是stdout的原因。

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

your not passing the address of the pointer. 你没有传递指针的地址。 It just passes the value in the memory to the function which is unncessary. 它只是将内存中的值传递给不需要的函数。

And your only initializing first variable of struct but while you are trying to free the memory you are unallocating memory which is not yet allocated (astruct[1] and so on till 100 ). 你唯一初始化struct的第一个变量,但是当你试图释放内存时,你正在分配尚未分配的内存(astruct [1],依此类推,直到100)。

When you use a malloc , it actually allocates a bit more memory than you you specified. 当您使用malloc时,它实际上分配的内存比您指定的多一点。 extra memory is used to store information such as the size of block, and a link to the next free/used block and sometimes some guard data that helps the system to detect if you write past the end of your allocated block. 额外内存用于存储诸如块大小之类的信息,以及指向下一个空闲/已使用块的链接,有时还有一些保护数据可帮助系统检测是否写入了已分配块的末尾。

If you pass in a different address, it will access memory that contains garbage, and hence its behaviour is undefined (but most frequently will result in a crash) 如果传入不同的地址,它将访问包含垃圾的内存,因此其行为未定义(但最常见的是导致崩溃)

To index and count an unsigned integer type is enough. 索引和计数无符号整数类型就足够了。 size_t is the type of choice for this as it is guaranteed to be larger enough to address/index every byte of memory/array's element on the target machine. size_t是这种选择的类型,因为它保证足够大以解决/索引目标机器上的内存/数组元素的每个字节。

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

Always properly initialise variables: 始终正确初始化变量:

struct myStruct astruct[100] = {0};

Several issues with the allocator: 分配器的几个问题:

  • Give it a chance to returned specific error codes. 给它一个返回特定错误代码的机会。 This typically is done by setting using the function returned value to to so. 这通常通过使用函数返回值进行设置来完成。
  • Use size_t for counters and indicies and sizes ("rows", "columns")(for why please see above). 使用size_t作为计数器和指示和大小(“行”,“列”)(为什么请参见上文)。
  • Do proper error checking. 做适当的错误检查。
  • Clean up in case an error occurs during work. 清理以防工作期间发生错误。
  • do not cast the value returned by malloc() , as in C it's not necessary, not recommended 不要malloc()返回的值,因为在C中没有必要,不推荐使用
  • Use perror() to log error, as it gets the most from the OS about the as possibe. 使用perror()来记录错误,因为它从操作系统中获得了关于as possibe的最多信息。

A possible to do this: 有可能做到这一点:

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

Two issues for the de-allocator: 解除分配器的两个问题:

  • Mark it's work as done be properly de-initilaising the pointer. 标记它的工作就像正确地去启动指针一样。
  • Perform validation of input prior to acting on it. 在对其进行操作之前执行输入验证。

A possible to do this: 有可能做到这一点:

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

Then use the stuff like this: 然后使用这样的东西:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM