Q我怎样才能动态分配一个多维数组?
A传统的解决方案是分配一个指针的指针数组[脚注],然后将每个指针初始化为动态分配的“行”。下面是一个二维的例子
#include <stdlib.h> int **array1 = malloc(nrows * sizeof(int *)); for(i = 0; i < nrows; i++) array1[i] = malloc(ncolumns * sizeof(int));(在实际代码中,当然,所有的malloc的返回值都会被检查。你也可以使用sizeof(*array1)和sizeof(**array1)来解决这个问题,而不是sizeof(int *)和sizeof(int);参见[脚注]。)
你可以通过一些显式的指针算术来保持数组内容的连续性,但这会使以后单独重分配行的操作更加困难。
int **array2 = malloc(nrows * sizeof(int *)); array2[0] = malloc(nrows * ncolumns * sizeof(int)); for(i = 1; i < nrows; i++) array2[i] = array2[0] + i * ncolumns;在任何一种情况下(即对于array1或和array2),都可以使用看起来正常的数组下标来访问动态数组的元素arrayx[i][j](其中 0 <= < i< nrowsand 0 <= < j< ncolumns)。这是对布局的示意性说明array1和和:
如果上述方案中双重间接引用对您来说不可接受[脚注],您可以使用一个单独的、动态分配的一维数组来模拟一个二维数组。
int *array3 = malloc(nrows * ncolumns * sizeof(int));但是,您现在必须手动执行下标计算,使用表达式访问第(其中 0 <= ,and 0 <= 个元素
array3[i * ncolumns + j],并且这个数组不一定能传递给期望多维数组的函数。(像宏
#define Arrayaccess(a, i, j) ((a)[(i) * ncolumns + (j)])这样的宏可以隐藏显式计算,但调用它需要圆括号和逗号,这看起来不像传统的 C 多维数组语法,而且宏至少需要访问一个维度。另请参见问题 6.19。)
还有一种选择是使用指向数组的指针
int (*array4)[NCOLUMNS] = malloc(nrows * sizeof(*array4));或者甚至是
int (*array5)[NROWS][NCOLUMNS] = malloc(sizeof(*array5));,但语法开始变得糟糕(对array5的访问看起来像(*array5)[i][j]),而且运行时最多只能指定一个维度。
对于所有这些技术,您当然可能需要记住在不再需要数组时释放它们;对于array1和和来说,这需要几个步骤(另请参见问题 7.23)。
for(i = 0; i < nrows; i++) free((void *)array1[i]); free((void *)array1); free((void *)array2[0]); free((void *)array2);此外,您不一定可以将动态分配的数组与常规的、静态分配的数组混合使用(请参见问题 6.20,以及问题 6.18)。
最后,在 C99 中,您可以使用可变长度数组。
所有这些技术都可以扩展到三维或更多维度。下面是第一种技术的三维版本(与此处展示的其他片段一样,它在实际程序中使用前需要进行错误检查)。
int ***a3d = (int ***)malloc(xdim * sizeof(int **)); for(i = 0; i < xdim; i++) { a3d[i] = (int **)malloc(ydim * sizeof(int *)); for(j = 0; j < ydim; j++) a3d[i][j] = (int *)malloc(zdim * sizeof(int)); }
另请参见问题 20.2。
参考文献:C9X Sec. 6.5.5.2