释放多维数组C.

时间:2016-11-07 05:07:32

标签: c multidimensional-array memory-leaks

我有一个名为Grid的结构,它包含一个2d字符串数组。我一直在搜索如何正确释放多维数组,并且似乎无法通过此过程找到问题,因为valgrind一直在检测错误和泄漏内存。提前谢谢!

  typedef struct Grid{
    int N;
    int M;
    char ***adj;
  }TGrid;

  TGrid* emptyGrid(int N, int M){
   int i,j;

   TGrid *Grid = malloc(sizeof(TGrid));
   Grid->N = N;
   Grid->M = M;
   Grid->adj = malloc(N * sizeof(char ***));

   for(i = 0; i < N; i++){
       Grid->adj[i] = malloc(M * sizeof(char **));
       for(j = 0; j < M; j++){
           Grid->adj[i][j] = malloc(10 * sizeof(char *));
       }
   }
   return Grid;
}


void freeGrid(TGrid *Grid){
   int i, j;

   for(i = 0; i < Grid->N; i++){
       for(j = 0; j < Grid->M; j++){
           free(Grid->adj[i][j]);
       }
       free(Grid->adj[i]);
   }

   free(Grid->adj);
   free(Grid);
}

4 个答案:

答案 0 :(得分:2)

malloc内存的方式不正确,应采取正确的方法:

TGrid* emptyGrid(int N, int M){
   int i,j;

   TGrid *Grid = malloc(sizeof(TGrid));
   Grid->N = N;
   Grid->M = M;
   Grid->adj = malloc(N * sizeof(char **));

   for(i = 0; i < N; i++){
       Grid->adj[i] = malloc(M * sizeof(char *));
       for(j = 0; j < M; j++){
           Grid->adj[i][j] = malloc(10 * sizeof(char));
       }
   }
   return Grid;
}

请注意,Grid->adj[i][j]始终指向10个字符的数组,您可以使用:

#include <stdio.h>
#include <stdlib.h>

typedef struct Grid{
    int N;
    int M;
    char (**adj)[10];
  }TGrid;

  TGrid* emptyGrid(int N, int M){
   int i;

   TGrid *Grid = malloc(sizeof(TGrid));
   Grid->N = N;
   Grid->M = M;
   Grid->adj = malloc(N * sizeof(char (*)[10]));

   for(i = 0; i < N; i++){
       Grid->adj[i] = malloc(M * sizeof(char[10]));
   }
   return Grid;
}


void freeGrid(TGrid *Grid){
   int i;

   for(i = 0; i < Grid->N; i++){
       free(Grid->adj[i]);
   }

   free(Grid->adj);
   free(Grid);
}

int main() {
    TGrid* t = emptyGrid(2,3);
    freeGrid(t);
    return 0;
}

但是,由于free收到void*参数,因此您的代码中必须包含其他内容。

答案 1 :(得分:2)

您的代码的一般结构很好,但sizeof下的类型是错误的。 malloc内存的一般习惯用法如下

T *p = malloc(N * sizeof *p);

或等同于

T *p = malloc(N * sizeof(T));

请注意,在后一种(基于类型的)变体中,sizeof下的星号比收件人指针类型少一个星号。

确切地说,在你的情况下它应该如何

Grid->adj = malloc(N * sizeof(char **));
/* Since `Grid->adj` is `char ***`, you should have `char **` under `sizeof` */
...
  Grid->adj[i] = malloc(M * sizeof(char *));
  /* Since `Grid->adj[i]` is `char **`, you should have `char *` under `sizeof` */
  ...
    Grid->adj[i][j] = malloc(10 * sizeof(char));
    /* Since `Grid->adj[i][j]` is `char *`, you should have `char` under `sizeof` */

如果那不是您所需要的,那么您的类型肯定有问题。如果不知道你的意图,就没办法说。

(我建议您使用第一种方法在sizeof下指定malloc - 使用表达式,而不是类型。这样您就不必计算星号。)

但是,在现实生活中,这种特定错误通常只会导致过度分配的内存。不应发生越界访问或内存泄漏。如果valgrind报告此类错误,那么此处也必须有其他工作。

答案 2 :(得分:1)

由于您尚未发布使用这些功能的代码,因此很难确定问题所在。

我想指出需要更改对malloc的调用。

你有:

Grid->adj = malloc(N * sizeof(char ***));

for(i = 0; i < N; i++){
   Grid->adj[i] = malloc(M * sizeof(char **));
   for(j = 0; j < M; j++){
       Grid->adj[i][j] = malloc(10 * sizeof(char *));
   }
}

这些电话需要更改为:

Grid->adj = malloc(N * sizeof(char **));

for(i = 0; i < N; i++){
   Grid->adj[i] = malloc(M * sizeof(char *));
   for(j = 0; j < M; j++){
       Grid->adj[i][j] = malloc(10 * sizeof(char));
   }
}

您可以使用以下编码样式来避免此类错误:

Grid->adj = malloc(N * sizeof(*(Grid->adj)));

for(i = 0; i < N; i++){
   Grid->adj[i] = malloc(M * sizeof(*(Grid->adj[i])));
   for(j = 0; j < M; j++){
       Grid->adj[i][j] = malloc(10 * sizeof(*(Grid->adj[i][j])));
   }
}

使用相同样式的简单案例:

char* cp = malloc(10*sizeof(*cp));

答案 3 :(得分:1)

您没有分配数组,而是分配基于指针的查找表。这样做的唯一原因是,如果您希望各个尺寸具有不同的长度(例如在字符串数组中)。如果你不需要它,你就不应该使用指针到指针表,因为它们很慢,容易出错并且不必要地复杂。

要分配实际的3D数组,您可以这样做:

char (*array)[Y][Z] = malloc ( sizeof(char[X][Y][Z] );
...
free(array);

要分配字符串数组,您可以这样做:

char** lookup = malloc ( sizeof( char*[N] ) );
for(size_t i=0; i<N; i++)
{
  lookup[i] = ...; // assign pointers to strings
}
...
free(lookup);

根据经验,只要程序包含两个以上的间接级别,程序设计就很可能很糟糕。