将不相邻的数组传递给期望真正的多维数组的函数
当使用 malloc
,calloc
和 realloc
分配多维数组时,常见的模式是使用多个调用分配内部数组(即使调用只出现一次,它可能在循环中):
/* Could also be `int **` with malloc used to allocate outer array. */
int *array[4];
int i;
/* Allocate 4 arrays of 16 ints. */
for (i = 0; i < 4; i++)
array[i] = malloc(16 * sizeof(*array[i]));
其中一个内部数组的最后一个元素与下一个内部数组的第一个元素之间的字节差异可能不是 0,因为它们与真实多维数组(例如 int array[4][16];
)相同:
/* 0x40003c, 0x402000 */
printf("%p, %p\n", (void *)(array[0] + 15), (void *)array[1]);
考虑到 int
的大小,你会得到 8128 字节(8132-4)的差异,这是 2032 个 int
大小的数组元素,这就是问题:真正的多维数组在元素之间没有间隙。
如果需要使用动态分配的数组,并且函数需要一个真正的多维数组,则应该分配 int *
类型的对象并使用 arithmetic 来执行计算:
void func(int M, int N, int *array);
...
/* Equivalent to declaring `int array[M][N] = {{0}};` and assigning to array4_16[i][j]. */
int *array;
int M = 4, N = 16;
array = calloc(M, N * sizeof(*array));
array[i * N + j] = 1;
func(M, N, array);
如果 N
是宏或整数文字而不是变量,则在分配指向数组的指针后,代码可以简单地使用更自然的 2-D 数组表示法:
void func(int M, int N, int *array);
#define N 16
void func_N(int M, int (*array)[N]);
...
int M = 4;
int (*array)[N];
array = calloc(M, sizeof(*array));
array[i][j] = 1;
/* Cast to `int *` works here because `array` is a single block of M*N ints with no gaps,
just like `int array2[M * N];` and `int array3[M][N];` would be. */
func(M, N, (int *)array);
func_N(M, array);
Version >= C99
如果 N
不是宏或整数文字,则 array
将指向可变长度数组(VLA)。这仍然可以通过转换到 int *
与 func
一起使用,而新功能 func_vla
将取代 func_N
:
void func(int M, int N, int *array);
void func_vla(int M, int N, int array[M][N]);
...
int M = 4, N = 16;
int (*array)[N];
array = calloc(M, sizeof(*array));
array[i][j] = 1;
func(M, N, (int *)array);
func_vla(M, N, array);
Version >= C11
注意 :从 C11 开始,VLA 是可选的。如果你的实现支持 C11 并将宏 __STDC_NO_VLA__
定义为 1,那么你将坚持使用前 C99 方法。