I am currently struggling to find a proper way to dynamically allocate a true 3D array in C89. The purpose of this is to create a storage for a 3D Cartesian grid. Is it possible to do so without the so-called three-star programming?
-
1What (do you think) is "a true 3D array"? How is it differ from simple arrays like `int hoge[64][64][64];`? – MikeCAT Feb 04 '21 at 19:22
-
1Whats wrong with tree-star? If you want 3D array, you need "pointer to pointer to pointer".. each of those will point to "pointer to pointer" and each of those would point to "pointer". whats wrong with that? – Gal Birka Feb 04 '21 at 19:24
-
1C89? What cruel situation are you stuck in? Do you need help? Blink three times if you need a rescue. – tadman Feb 04 '21 at 19:24
-
Not possible to `malloc` a 3D array without `int***` in standard C. Sorry. – DarkAtom Feb 04 '21 at 19:25
-
1There's only semantic differences between `int p[X][Y][Z]` and `int p[X * Y * Z]`, they're both "3D" arrays. – tadman Feb 04 '21 at 19:25
-
@DarkAtom This is not true. – Eugene Sh. Feb 04 '21 at 19:26
-
@EugeneSh. Allocating a 1D array and treating it as 3D by indexing it manually isn't the same as allocating a 3D array. – DarkAtom Feb 04 '21 at 19:27
-
1`void*` may be useful to hide `int**` and avoid three-star, but I won't recommend this. – MikeCAT Feb 04 '21 at 19:27
-
2@DarkAtom You can do something like `int (*p)[10][10][10] = malloc(10*10*10*sizeof(int));` - and `p` will be a pointer to a perfectly contiguous 3D array with all the typechecking. – Eugene Sh. Feb 04 '21 at 19:30
-
@EugeneSh. But then what is the point of dynamic memory allocation? You could simply declare a static array with those bounds. – DarkAtom Feb 04 '21 at 19:34
-
@DarkAtom To see what Eugene is driving at, see my recent answer: https://stackoverflow.com/questions/66017818/how-to-display-the-individual-elements-of-two-identical-columns-inside-a-2d-arra/66035985#66035985 Look at the code in the UPDATE section, particularly the `ARRDEF` macro. – Craig Estey Feb 04 '21 at 19:37
-
@DarkAtom This is another story. You can have it VLA-like `int (*p)[x][y][z] = malloc(x*y*z*sizeof(int))`. But without the downsides of VLAs related to their stack nature. But well, not in C89. – Eugene Sh. Feb 04 '21 at 19:37
-
1From my current understanding a pointer-to-pointer isn't an array so in this way I am only mimicking them.. – miker Feb 04 '21 at 19:40
-
@miker You are very right about it. – Eugene Sh. Feb 04 '21 at 19:40
3 Answers
The function malloc does not know what kind of an array you are trying to allocate. It just allocates an extent of memory of the size specified by the user.
What you need is to declare correctly the pointer that will point to the allocated memory that you could use an expression like
a[i][j][k]
to access elements of the allocated array where i, j, and k are some indices.
You can allocate a three dimensional array for example the following way
enum { N1 = 2, N2 = 3, N3 = 4 };
int ( *a )[N2][N3] = malloc( sizeof( int[N1][N2][N3] ) );
or
int ( *a )[N2][N3] = malloc( N1 * sizeof( int[N2][N3] ) );
or
int ( *a )[N2][N3] = malloc( N1 * sizeof( *a ) );
or like
int ( *a )[N2][N3] = malloc( N1 * N2 * sizeof( int[N3] ) );
or
int ( *a )[N2][N3] = malloc( N1 * N2 * sizeof( **a ) );
or even like
int ( *a )[N2][N3] = malloc( N1 * N2 * N3 * sizeof( int ) );
or
int ( *a )[N2][N3] = malloc( N1 * N2 * N3 * sizeof( ***a ) );
If your compiler supports variable length arrays then it is not necessary that N1, N2, and N3 would be integer constant expressions.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
enum { N1 = 2, N2 = 3, N3 = 4 };
int ( *a )[N2][N3];
a = malloc( sizeof( int[N1][N2][N3] ) );
free( a );
a = malloc( N1 * sizeof( int[N2][N3] ) );
free( a );
a = malloc( N1 * sizeof( *a ) );
free( a );
a = malloc( N1 * N2 * sizeof( int[N3] ) );
free( a );
a = malloc( N1 * N2 * sizeof( **a ) );
free( a );
a = malloc( N1 * N2 * N3 * sizeof( int ) );
free( a );
a = malloc( N1 * N2 * N3 * sizeof( ***a ) );
free( a );
return 0;
}
If your compiler does not support variable length arrays and you need to determine sizes of a three-dimensional array at run-time then you can allocate a one-dimensional array and using an index expression simulate a three dimensional array or you will need to allocate arrays of arrays.
For example
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
enum { N1 = 2, N2 = 3, N3 = 4 };
int ***a = malloc( N1 * sizeof( int ** ) );
for ( size_t i = 0; i < N1; i++ )
{
a[i] = malloc( N2 * sizeof( int * ) );
for ( size_t j = 0; j < N2; j++ )
{
a[i][j] = malloc( N3 * sizeof( int ) );
}
}
//...
for ( size_t i = 0; i < N1; i++ )
{
for ( size_t j = 0; j < N2; j++ )
{
free( a[i][j] );
}
free( a[i] );
}
free( a );
return 0;
}

- 301,070
- 26
- 186
- 335
-
Thank You for Your proposals but sadly it seems they don't need my needs... My aim is to allocate the array once its dimensions are determined so N1, N2, N3 won't be constant expressions. Im C89 I also cannot decalere int (*a) [N2][N3] after I determine the required dimensions. – miker Feb 04 '21 at 20:05
-
1@miker As I wrote in the answer in this case you have only two choices either allocate one one-dimensional array and use an expression of indices that will simulate an access of a three dimensional array or allocate one-dimensional arrays )of pointers) of arrays. – Vlad from Moscow Feb 04 '21 at 20:08
There are a few options. Some may or may not suit your needs.
Static arrays
If the size of the array is a compile-time constant, you can declare it like this:
int arr[3][4][5];
Variable-length arrays
Same as above, but the array size doesn't need to be a compile-time constant. This only works for local arrays and only in C99, though, so it won't work for you.
int arr[n][m][p];
Or, if you want it dynamically allocated, as suggested by @Eugene Sh:
int (*arr)[m][p] = malloc(sizeof(int) * n * m * p);
Dynamic memory allocation
Using malloc
:
int*** arr = malloc(sizeof(int) * n * m * p);
Or, if you don't want triple pointers:
int* arr = malloc(sizeof(int) * n * m * p);
But this array needs to be indexed as arr[i*p + j*m + k]
instead of the usual arr[i][j][k]
.

- 2,589
- 1
- 11
- 27
By a "true" 3D array I'm assuming you mean that all the elements are in one contiguous block. In that case your best option would be something like this:
/**
* Allocate an NxRxC array of some arbitrary type T
*/
T (*arr)[R][C] = malloc( sizeof *arr * N );
which gives you
T (*)[R][C] T
+---+ +---+
arr: | | ----------->| | arr[0][0][0]
+---+ +---+
| | arr[0][0][1]
+---+
...
+---+
| | arr[0][0][C-1]
+---+
| | arr[0][1][0]
+---+
...
+---+
| | arr[0][R-1][C-1]
+---+
| | arr[1][0][0]
+---+
...
You would only use a triple pointer for a piecemeal, "jagged" array allocation (error checking omitted for brevity):
T ***a = malloc( sizeof *a * N )
for ( size_t i = 0; i < N; i++ )
{
a[i] = malloc( sizeof *a[i] * R );
for ( size_t j = 0; j < C; j++ )
{
a[i][j] = malloc( sizeof *a[i][j] * C );
}
}
which gives you something like this:
T *** T** T* T
+---+ +---+ +---+ +---+---+---+---+---+
a: | |------>| | a[0] ----->| | a[0][0] ---->| | | | | |...
+---+ +---+ +---+ +---+---+---+---+---+
| | a[1] --+ | | a[0][1] --+
+---+ | +---+ | +---+---+---+---+---+
... | ... +->| | | | | |...
| +---+---+---+---+---+
|
| +---+ +---+---+---+---+---+
+-->| | a[1][0] ---->| | | | | |...
+---+ +---+---+---+---+---+
| | a[1][1] --+
+---+ | +---+---+---+---+---+
... +->| | | | | |...
+---+---+---+---+---+
You would use this second method when rows don't have to be the same length, or when you absolutely cannot allocate the whole array in a single contiguous block.

- 119,563
- 19
- 122
- 198