secluded secluded - 1 year ago 44
C Question

allocating memory for a 3D array in C using pointers?

I have the following piece of code in C:

double ***grid
grid = calloc(nx, sizeof(double**))
for (int i = 0; i < nx; ++i) {
grid[i] = calloc(ny,sizeof(double*));
for (int j = 0; j < ny; ++j) {
grid[i][j] = calloc(nz,sizeof(double));

What I don't understand is that why can't we write
? Isn't it true that each member of grid is a "pointer to pointer"? Also shouldn't we have
grid[i][j] = calloc(nz,sizeof(double*))

The code works fine when I use
in its current form but I'm confused about why. I'm new to C, so I'd appreciate all forms of explanation.

EDIT: one line was missing:
grid = calloc(nx, sizeof(double**))

Answer Source

First you're missing the first alloc: grid = calloc(nx, sizeof(double **)); but I'm not sure this is the point since the code does not even compile (missing semicolon after grid declaration so it must have been allocated somewhere else)

Then to answer your question, allocation returns a pointer on the object, which adds an extra *, but you have to specify the size of the element for calloc to make the calculations (ny*sizeof(object))


would work, because size of pointer on pointer of double is the same as pointer of double, but it is not perfect.

if you have an array of int that you allocate like this:

int *array = calloc(ny,sizeof(int *))

it will work all right on most platforms, but if you are on a 64-bit architecture with a standard 32-bit int (windows 64-bit box for instance, gcc 64 bit compiler), since pointers are 64 bit, it will allocate twice as much memory as you really need. The correct syntax in that case is:

int *array = calloc(ny,sizeof(int))

because the element is an int, and it returns a pointer on int (int *)

So, now, recurrently, when you're adding a star on the left, you add a star on the right:

int **array = calloc(ny,sizeof(int *))
int ***array = calloc(ny,sizeof(int **))

and so on...

Small personal story: Some nasty crashes were encountered when migrating from 32-bit to 64-bit back in the days when people used to use:

int **array = calloc(ny,sizeof(int))   // WRONG!!

which worked while everything was 32-bit. When sizeof(int *) was increased to 8 bytes because of 64 bit arch, only half of the size was allocated, which could result in very funny bugs.