# Thread: Dynamically allocate Large 4-D arrays

1. ## Dynamically allocate Large 4-D arrays

Hello,

For a project I am working on, I need to be able to dynamically allocate large 4-dimensional arrays. The code I am using to do this is:

Code:
```void allocate_data_mem(size_t count0, size_t count1, size_t count2, size_t count3, double *****data)
{
int i, j, k, l;

*data = (double ****)malloc(count2*sizeof((*data)));
if ((*data) != NULL) {
for(i = 0; i < count2; i++) {
(*data)[i] = (double ***)malloc(count3*sizeof((*data)));
if ((*data)[i] != NULL) {
for(j = 0; j < count3; j++) {
(*data)[i][j] = (double **)malloc(count1*sizeof((*data)));
if ((*data)[i][j] != NULL) {
for (k = 0; k < count1; k++) {
(*data)[i][j][k] = (double *)malloc(count0*sizeof((*data)));
if ((*data)[i][j][k] == NULL) {
printf("Mem allocation failed\n");
exit(1);
}
}
}
else {
printf("Mem allocation failed\n");
exit(1);
}
}
}
else {
printf("Mem allocation failed\n");
exit(1);
}
}
}
else {
printf("Mem allocation failed\n");
exit(1);
}

}```
It works fine, but the problem is it is slow. For a 300x400x30x10 array, this code will use 3.6 million malloc calls and takes about 0.5 seconds to complete. The program as a whole will do this many times, so the time adds up.

Is there another way to accomplish this using fewer mallocs?

Thanks. 2. Is there another way to accomplish this using fewer mallocs?
Yes - multiply all of your dimensions together, and allocate the space in one large chunk. But remember that just getting that much memory might cause delays also - but at least all your allocation would be done in one large chunk.

Remember that when you're working with arrays, you really just have a pointer to the beginning and an offset. Let's say I have a an array of chars:
Code:
`char string;`
If I refer to "string" it's just a pointer to the beginning of the array, and is equal to &string. But when I try to access string or string, it's the same as dereferencing the pointers "string+10" or "string+20". So you could allocate a huge chunk of memory with one pointer, and then work with various arrays by using the offsets. So given your example dimensions, you could access every element by adding 1 to the offset every time. You could access each 1-d array by adding 10 every time, each 2-d array by adding 30 every time, etc... Just be very careful with your bounds. 3. You can malloc each dimension separately as a single contiguous block (so a 4D array would be just 4 mallocs).

Example for 2D
Code:
```#include <stdio.h>
#include <stdlib.h>

int **allocate2Darray ( int rows, int cols ) {
int **result;
int r, *rp;  // initialise each row pointer

result = malloc( rows * sizeof *result );
result = malloc( rows * cols * sizeof *result );
for ( r = 0, rp = result ; r < rows ; r++, rp += cols ) {
result[r] = rp;
}
return result;
}

void free2Darray ( int **array ) {
free( array );
free( array );
}

#define MAX_R 5
#define MAX_C 16
int main(int argc, char **argv) {
int **a = allocate2Darray( MAX_R, MAX_C );
int r, c;
for ( r = 0 ; r < MAX_R ; r++ ) {
for ( c = 0 ; c < MAX_C ; c++ ) {
a[r][c] = 0;
}
}
printf( "The pitch between rows is %x bytes\n", MAX_C * sizeof(int) );
for ( r = 0 ; r < MAX_R ; r++ ) {
printf( "Row %d begins at %p\n", r, (void*)a[r] );
}
free2Darray( a );
return 0;
}```
3D would have a malloc for result and so on.

It's quite nice in that it doesn't involve any pointer casting and do-it-yourself pointer arithmetic to make it work  4. A brief skimming reminded me of this:
4-dimensional array contiguous allocation 5. Dagnabbit, how come you could find it and I couldn't  6. here's another way if you know the dimensions at compile time (doesn't look like you do, but I'm putting it out there just in case)
Code:
```double (*array) = malloc(sizeof *array);
double (*array2) = malloc (sizeof(*array2) * 300);
(*array) = 2.0;
array2 = 1.0;
free(array);
free(array2);``` 7. Have you thought about putting the data into a struct, and then just using a 1D array of those structs?

array[1d][2d][3d][4d], to access some data (each Nd being an index), it would be:

array[1d].struct member4

Seems to simplify the whole thing. 8. Then it just becomes a 2d array - 1 dimension of structs, and 1 dimension of members in the struct. Each dimension was a different length. 9. Whoa! Will you really have all 300x400x30x10 slots in the array filled at once?! That's 36 Million items!
Or perhaps what you really need is some kind of sparse array... That's something that acts like an array but places that aren't occupied by items mostly don't count towards the space used. I made a multiway-trie class that handles such functionality.

If it's not sparse that you need, then at the very least combine some of the dimensions together into bitmap style array indexing. Maybe combine the last 3 dimensions together. That's 300 mallocs to 120000 items each - much more manageable. Of course it depends on your access patterns, e.g. which way round your loops are nested. Popular pages Recent additions 