prev up next   top/contents search

comp.lang.c FAQ 列表· 问题 6.16

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;
在任何一种情况下(即对于array1array2),都可以使用看起来正常的数组下标来访问动态数组的元素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


prev up next   contents search
关于此 FAQ 列表   关于 Eskimo   搜索   反馈   版权

Eskimo North 托管