When allocating multidimensional arrays with malloc
, calloc
, and realloc
, a common pattern is to allocate the inner arrays with multiple calls (even if the call only appears once, it may be in a loop):
/* 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]));
The difference in bytes between the last element of one of the inner arrays and the first element of the next inner array may not be 0 as they would be with a "real" multidimensional array (e.g. int array[4][16];
):
/* 0x40003c, 0x402000 */
printf("%p, %p\n", (void *)(array[0] + 15), (void *)array[1]);
Taking into account the size of int
, you get a difference of 8128 bytes (8132-4), which is 2032 int
-sized array elements, and that is the problem: a "real" multidimensional array has no gaps between elements.
If you need to use a dynamically allocated array with a function expecting a "real" multidimensional array, you should allocate an object of type int *
and use arithmetic to perform calculations:
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);
If N
is a macro or an integer literal rather than a variable, the code can simply use the more natural 2-D array notation after allocating a pointer to an array:
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);
If N
is not a macro or an integer literal, then array
will point to a variable-length array (VLA). This can still be used with func
by casting to int *
and a new function func_vla
would replace 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);
Note: VLAs are optional as of C11. If your implementation supports C11 and defines the macro __STDC_NO_VLA__
to 1, you are stuck with the pre-C99 methods.