提问人:Mike 提问时间:9/17/2012 更新时间:7/23/2019 访问量:7634
如何在 C 中正确设置、访问和释放多维数组?
How do I correctly set up, access, and free a multidimensional array in C?
问:
我已经看到了很多关于 C 语言中多维数组的“我的代码有什么问题”的问题。出于某种原因,人们似乎无法理解这里发生的事情,所以我决定回答这个问题作为其他人的参考:
如何在 C 中正确设置、访问和释放多维数组?
如果其他人有有用的建议,请随时发帖!
答:
从静态上讲,这很容易理解:
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
现在让我们从指针的角度来看一下:
括号是一个非常好的结构,可以帮助简化事情,但是当我们需要在动态环境中工作时,它没有帮助,因此我们需要从指针的角度来考虑这一点。如果我们想存储整数的“行”,我们需要一个数组:
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 的指针,我们可以将这个数组设置为动态长度,并给它一些内存:
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
所以现在我们有一个动态的一维数组;单行。但是我们想要很多行,而不仅仅是一行,我们不知道有多少行。这意味着我们需要另一个动态的一维数组,该数组的每个元素都将是一个指向一行的指针。
//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]
现在剩下要做的就是编写代码来执行这些动态分配:
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!)
}
现在要做的最重要的事情之一是确保我们在完成后释放内存。每个级别的调用数应相同,并且调用应按 FILO 顺序排列(与 malloc 调用相反):malloc()
free()
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;
评论
int**
int (*)[]
在 C99 之后的 C 语言中,即使是动态多维数组也可以很容易地一次性分配并释放: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);
评论
double* A = malloc(x*y*sizeof(double));
double (*A)[n]
n
enum
double (*A)[] =
在 C89 中,至少有四种不同的方法可以创建或模拟多维数组。
一种是“单独分配每一行”,Mike在他的回答中描述了这一点。它不是一个多维数组,它只是模仿一个数组(特别是它模仿访问元素的语法)。在每行都有不同大小的情况下,它可能很有用,所以你不是在表示一个矩阵,而是在表示一个具有“参差不齐边缘”的东西。
一种是“分配多维数组”。它看起来像这样:
int (*rows)[NUM_ROWS][NUM_COLS] = malloc(sizeof *rows);
...
free(rows);
则访问元素 [i,j] 的语法为 。在 C89 中,必须在编译时知道 和。这是一个真正的二维数组,并且是指向它的指针。(*rows)[i][j]
NUM_COLS
NUM_ROWS
rows
一种是“分配行数组”。它看起来像这样:
int (*rows)[NUM_COLS] = malloc(sizeof(*rows) * NUM_ROWS);
...
free(rows);
则访问元素 [i,j] 的语法为 。在 C89 中,必须在编译时知道。这是一个真正的二维阵列。rows[i][j]
NUM_COLS
一种是“分配一个一维数组并假装”。它看起来像这样:
int *matrix = malloc(sizeof(int) * NUM_COLS * NUM_ROWS);
...
free(matrix);
则访问元素 [i,j] 的语法为 。这(当然)不是真正的二维数组。在实践中,它具有与一个相同的布局。matrix[NUM_COLS * i + j]
评论
如果你想使用 typedef'd 数组,那就更简单了。
假设你的代码中有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]... */
}
因为是指向 u 矩阵的指针,并且优先级低于pArr
*
[]
;
这就是为什么一个常见的模式习惯语是 typedef 行:
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);
评论
根据 Jen 的回答,如果你想为 3D 阵列分配空间,以同样的方式,你可以这样做
int(*A)[n][n] = malloc(sizeof(int[num_of_2D_arrays][n][n]));
for (size_t p = 0; p < num_of_2D_arrays; p++)
for (size_t i = 0; i < n; i++)
for (size_t j = 0; j < n; j++)
A[p][i][j] = p;
for (size_t p = 0; p < num_of_2D_arrays; p++)
printf("Outter set %lu\n", p);
for (size_t i = 0; i < n; i++)
for (size_t j = 0; j < n; j++)
printf(" %d", A[p][i][j]);
printf("\n");
free(A);
评论