如何正确设置,访问和释放C中的multidimensional array?

我已经看到了关于C中multidimensional array的问题“我的代码出了什么问题”的几十个问题。由于某些原因,人们似乎无法把头在这​​里发生的事情,所以我决定回答这个问题,作为对其他人的参考:

如何正确设置,访问和释放C中的multidimensional array?

如果别人有帮助的build议,请随时张贴!

在C99以后,即使dynamicmultidimensional array也可以用malloc轻松分配,并且free释放:

 double (*A)[n] = malloc(sizeof(double[n][n])); for (size_t i = 0; i < n; ++i) for (size_t j = 0; j < n; ++j) A[i][j] = someinvolvedfunction(i, j); free(A); 

在C89中至less有四种不同的方式来创build或模拟multidimensional array。

一个是“分别分配每一行”,由Mike在他的回答中描述。 它不是一个multidimensional array,它只是模仿一个(特别是它模仿访问一个元素的语法)。 在每一行具有不同的大小的情况下,它可能是有用的,所以你不是表示一个matrix,而是具有“粗糙边缘”的东西。

一个是“分配一个multidimensional array”。 它看起来像这样:

 int (*rows)[NUM_ROWS][NUM_COLS] = malloc(sizeof *rows); ... free(rows); 

那么访问元素[i,j]的语法是(*rows)[i][j] 。 在C89中,编译时必须知道NUM_COLSNUM_ROWS 。 这是一个真正的二维数组, rows是一个指向它的指针。

一个是“分配行数组”。 它看起来像这样:

 int (*rows)[NUM_COLS] = malloc(sizeof(*rows) * NUM_ROWS); ... free(rows); 

那么访问元素[i,j]的语法是rows[i][j] 。 在C89中,编译时必须知道NUM_COLS 。 这是一个真正的二维数组。

一个是“分配一个一维数组并假装”。 它看起来像这样:

 int *matrix = malloc(sizeof(int) * NUM_COLS * NUM_ROWS); ... free(matrix); 

那么访问元素[i,j]的语法是matrix[NUM_COLS * i + j] 。 这(当然)不是一个真正的二维数组。 在实践中,它具有与一个相同的布局。

静态地说 ,这很容易理解:

 int mtx[3][2] = {{1, 2}, {2, 3}, {3, 4}}; 

没有什么复杂的。 3行2列; 数据在第一列: 1, 2, 3 ; 数据在第二栏: 2, 3, 4 。 我们可以通过相同的构造来访问元素:

 for(i = 0; i<3; i++){ for(j = 0; j<2; j++) printf("%d ", mtx[i][j]); printf("\n"); } //output //1 2 //2 3 //3 4 

现在让我们看看这个指针

括号是一个非常好的结构来帮助简化事情,但是当我们需要在一个dynamic的环境中工作时,这并没有什么帮助,所以我们需要用指针来考虑这个问题。 如果我们想存储一个整数的“行”,我们需要一个数组:

 int row[2] = {1,2}; 

你知道吗? 我们可以像访问指针一样访问它。

 printf("%d, %d\n",*row,*(row+1)); //prints 1, 2 printf("%d, %d\n",row[0],row[1]); //prints 1, 2 

现在,如果我们不知道一行中的值的数量,如果我们有一个指向int的指针,我们可以使这个数组成为一个dynamic的长度,我们给它一些内存:

 int *row = malloc(X * sizeof(int)); //allow for X number of ints *row = 1; //row[0] = 1 *(row+1) = 2; //row[1] = 2 … *(row+(X-1)) = Y; // row[x-1] = Some value y 

所以现在我们有一个dynamic的一维数组; 单排。 但是我们需要很多行,而不是一个,我们不知道有多less。 这意味着我们需要另一个dynamic的1维数组,数组中的每个元素将是一个指向一行的指针。

 //we want enough memory to point to X number of rows //each value stored there is a pointer to an integer int ** matrix = malloc(X * sizeof(int *)); //conceptually: (ptr to ptr to int) (pointer to int) **matrix ------------> *row1 --------> [1][2] *row2 --------> [2][3] *row3 --------> [3][4] 

现在剩下要做的就是编写执行这些dynamic分配的代码:

 int i, j, value = 0; //allocate memory for the pointers to rows int ** matrix = malloc(Rows * sizeof(int*)); //each row needs a dynamic number of elements for(i=0; i<Rows; i++){ // so we need memory for the number of items in each row… // we could call this number of columns as well *(matrix + i) = malloc(X * sizeof(int)); //While we're in here, if we have the items we can populate the matrix for(j=0; j<X; j++) *(*(matrix+i)+j) = value; // if you deference (matrix + i) you get the row // if you add the column and deference again, you // get the actual item to store (not a pointer!) } 

现在要做的最重要的事情之一就是确保我们完成时释放内存。 malloc()每个级别应该有相同数量的free()调用,并且调用应该在FILO顺序(malloc调用的反向)中:

 for(i=0; i<Rows; i++) free(*(matrix + i)); free(matrix); //set to NULL to clean up, matrix points to allocated memory now so let's not use it! matrix = NULL; 

如果你想使用typedef的数组,它更简单。

假设你的代码中有typedef int LabeledAdjMatrix[SIZE][SIZE];

然后你可以使用:

 LabeledAdjMatrix *pMatrix = malloc(sizeof(LabeledAdjMatrix)); 

那么你可以写:

 for (i=0; i<SIZE; i++) { for (j=0; j<SIZE; j++) (*parr)[i][j] = k++; /* or parr[0][i][j]... */ } 

因为pArr是一个指向你matrix的指针, *优先级低于[] ;

这就是为什么一个常用的习惯用法是键入这个行:

 typedef int LabeledAdjRow[SIZE]; 

那么你可以写:

 LabeledAdjRow *pMatrix = malloc(sizeof(LabeledAdjRow) * SIZE); for (i=0; i<SIZE; i++) { for (j=0; j<SIZE; j++) parr[i][j] = k++; } 

你可以直接memcpy

 LabeledAdjRow *pOther = malloc(sizeof(LabeledAdjRow) * SIZE); memcpy(pOther, pMatrix, sizeof(LabeledAdjRow) * SIZE);