將不相鄰的陣列傳遞給期望真正的多維陣列的函式
當使用 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 方法。