# 4-dimensional array contiguous allocation

This is a discussion on 4-dimensional array contiguous allocation within the C Programming forums, part of the General Programming Boards category; Hi all, I was wondering if anyone could help me to allocate a 4-dimensional array as a contiguous block of ...

1. ## 4-dimensional array contiguous allocation

Hi all,
I was wondering if anyone could help me to allocate a 4-dimensional array as a contiguous block of memory. I've figured out how to do this for the 3-dimensional case (see code below), but am having trouble extending to 4-d. Pointer aritmetic is not my forte!
Thanks!

Code:
```//matrix size is x*y*z
double ***bigMatrix;
bigMatrix = (double***) malloc(x*sizeof(double**));
bigMatrix[0] = (double**)malloc(x*y*sizeof(double*));
bigMatrix[0][0] = (double*)malloc(x*y*z*sizeof(double));

for(j=1; j<y; j++)
bigMatrix[0][j]=bigMatrix[0][j-1]+z;
for(i=1; i<x; i++){
bigMatrix[i]=bigMatrix[i-1]+y;
bigMatrix[i][0]=bigMatrix[i-1][0]+y*z;
for(j=1; j<y; j++){
bigMatrix[i][j]=bigMatrix[i][j-1]+x;
}
}```

2. That is not guaranteed to create the array in contiguous memory. Subsequent calls to malloc() don't necessarily have to allocate memory right up against or even near previous allocations.

And aren't you increasing the size backwards? The only way to really do it is in one malloc() call, or one malloc() call followed by realloc() calls.

Code:
`Something like: ptr = malloc(dim1_size * dim2_size * dim3_size * dim4_size * element_size);`

3. Hey itsme86,
This is a contiguous allocation; there is only one malloc call where doubles are actually allocated. The other malloc calls are there to set up the pointers so that the notation "bigMatrix[i][j][k][l]" can be used. Referencing bigMatrix[0][0] will allow access to a contiguous block of x*y*z doubles.
Trust me, it works :-)
Your code will only allow the notation "ptr[i]"
Shaun

4. I have no doubt that your code works, but what you have is a contiguous array of a contiguous array of a contiguous array of doubles. That is not the same thing as a contiguous 3-dimensional array.

5. Okay, well we won't argue over semantics, but it remains that there is a single call where a block of doubles is allocated contiguously. The pointers can indeed be seen as separate arrays if you want, but they don't contain the data; they set up the indexing structure. The actually data is lined up together in memory.
As I said, we won't argue, as this isn't getting my question answered

6. ## 4-dimensional allocation

Hello,

Pointers are my forte. So maybe I can help. I've always liked dealing with multi-dimensional arrays. Though, I've never actually tested pointer allocation. Today, I have. The following is an example, that should help you learn the general concept:
Code:
```#include <stdio.h>
#include <stdlib.h>

/*
Our example.

int arr[2][2][3][4] = {
{
{ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} },
{ {12, 13, 14, 15}, {16, 17, 18, 19}, {20, 21, 22, 23} },
},
{
{ {24, 25, 26, 27}, {28, 29, 30, 31}, {32, 33, 34, 35} },
{ {36, 37, 38, 39}, {40, 41, 42, 43}, {44, 45, 46, 47} },
}
};
*/

int main() {
/* Local variables */
int i=0, j=0, k=0, l=0, f, m=0;
int ****arr = NULL;

/* arr[2] */
arr = malloc(2 * sizeof *arr);
if (arr) {
/* arr[2][2] */
for (i = 0; i < 2; i++) {
/* Allocate memory */
arr[i] = malloc(2 * sizeof *arr);

/* If allocation failed */
if (arr[i] == NULL) {
/* Free any memory that was previously used */
for (f = i; f >= 0; f--) {
if (arr[f] != NULL) {
free(arr[f]);
arr[f] = NULL;
}
}
/* Free any memory that was previously used from beginning */
if (arr != NULL) {
free(arr);
arr = NULL;
}

/* Terminate program */
return 0;
}

/* arr[2][2][3] */
for (j = 0; j < 2; j++) {
/* Allocate memory */
arr[i][j] = malloc(3 * sizeof *arr);

/* If allocation failed */
if (arr[i][j] == NULL) {
/* Free any memory that was previously used */
for (f = j; f >= 0; f--) {
if (arr[i][f] != NULL) {
free(arr[i][f]);
arr[i][f] = NULL;
}
}
/* Free any memory that was previously used in previous loop */
for (f = i; f >= 0; f--) {
if (arr[f] != NULL) {
free(arr[f]);
arr[f] = NULL;
}
}
/* Free any memory that was previously used from beginning */
if (arr != NULL) {
free(arr);
arr = NULL;
}

/* Terminate program */
return 0;
}

/* arr[2][2][3][4] */
for (k = 0; k < 3; k++) {
/* Allocate memory */
arr[i][j][k] = malloc(4 * sizeof *arr);

/* If allocation failed */
if (arr[i][j][k] == NULL) {
/* Free any memory that was previously used */
for (f = k; f >= 0; f--) {
if (arr[i][j][f] != NULL) {
free(arr[i][j][f]);
arr[i][j][f] = NULL;
}
}
/* Free any memory that was previously used */
for (f = j; f >= 0; f--) {
if (arr[i][f] != NULL) {
free(arr[i][f]);
arr[i][f] = NULL;
}
}
/* Free any memory that was previously used in previous loop */
for (f = i; f >= 0; f--) {
if (arr[f] != NULL) {
free(arr[f]);
arr[f] = NULL;
}
}
/* Free any memory that was previously used from beginning */
if (arr != NULL) {
free(arr);
arr = NULL;
}

/* Terminate program */
return 0;
}
}
}
}
}else {
return 0;
}

/* Make sure we can write without failure */
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 3; k++) {
for (l = 0; l < 4; l++) {
arr[i][j][k][l] = m++;
}
}
}
}

/* Print array style for example sake */
printf("In example to: int arr[2][2][3][4];\n\n");
printf("int ****arr = {\n");
printf("\t{\n");
printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[0][0][0][0],
arr[0][0][0][1], arr[0][0][0][2], arr[0][0][0][3], arr[0][0][1][0], arr[0][0][1][1],
arr[0][0][1][2], arr[0][0][1][3], arr[0][0][2][0], arr[0][0][2][1], arr[0][0][2][2],
arr[0][0][2][3]);
printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[0][1][0][0],
arr[0][1][0][1], arr[0][1][0][2], arr[0][1][0][3], arr[0][1][1][0], arr[0][1][1][1],
arr[0][1][1][2], arr[0][1][1][3], arr[0][1][2][0], arr[0][1][2][1], arr[0][1][2][2],
arr[0][1][2][3]);
printf("\t},\n");
printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[1][0][0][0],
arr[1][0][0][1], arr[1][0][0][2], arr[1][0][0][3], arr[1][0][1][0], arr[1][0][1][1],
arr[1][0][1][2], arr[1][0][1][3], arr[1][0][2][0], arr[1][0][2][1], arr[1][0][2][2],
arr[1][0][2][3]);
printf("\t\t{ {%d, %d, %d, %d}, {%d, %d, %d, %d}, {%d, %d, %d, %d} },\n", arr[1][1][0][0],
arr[1][1][0][1], arr[1][1][0][2], arr[1][1][0][3], arr[1][1][1][0], arr[1][1][1][1],
arr[1][1][1][2], arr[0][0][1][3], arr[1][1][2][0], arr[1][1][2][1], arr[1][1][2][2],
arr[1][1][2][3]);
printf("\t}\n};");

/* Free Memory */
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 3; k++) {
free(arr[i][j][k]);
arr[i][j][k] = NULL;
}
free(arr[i][j]);
arr[i][j] = NULL;
}
free(arr[i]);
arr[i] = NULL;
}
free(arr);
arr = NULL;

return 0;
}```
Code 1.1: Allocating 4-dimensional pointer

- Stack Overflow

7. Well, here's one way you could do it:
Code:
```#include <stdio.h>
#include <stdlib.h>

int main(void)
{
int w = 5, x = 7, y = 10, z = 8;
int ****array;
int i, j, k;

array = malloc(sizeof(double ***) * w);

for(i = 0;i < w;++i)
{
array[i] = malloc(sizeof(double **) * x);

for(j = 0;j < x;++j)
{
array[i][j] = malloc(sizeof(double *) * y);

for(k = 0;k < y;++k)
array[i][j][k] = malloc(sizeof(double) * z);
}
}

// rest of code goes here. Don't forget to free every single allocation.

return 0;
}```

8. Hey Stack Overflow:
That looks really good; thanks a million!
One question though; is the data gauranteed to be contiguous. I'm not familiar with the notation you used in the malloc calls. What does "sizeof *arr" return? I'm guessing it will be a pointer to the currently located array, and I can kinda see how this is working. Where is the actual dataspace being allocated though? In the call "arr[i][j][k] = malloc(4 * sizeof* arr);", is the *arr actually representing the data type? If so, I guess that that's the only place where something equivalent to malloc(v*x*y*z*sizeof(int)) is called. Just confirm that this is your understanding also.
If I've understood correctly, then this is a really niftly piece of code, and a pretty intuitive way to do what I wanted to do. Cheers!

9. itsme86: you have "y" calls to malloc(sizeof(double) * z);, and therefore your data is not guaranteed to be contiguous.

10. Well I'm still not clear on which parts of the array you want to be contiguous. I don't only have "y" calls to malloc(sizeof(double) * z);. Don't forget that it's in a nested loop so there's actually w*x*y calls to it, which means that the array can hold w*x*y*z doubles, which is what I thought you were looking for.

11. Oh, actually Stack Overflow, I read through your code wrong. Your code won't give contiguous dataspace at all. I wonder can I use that code to allocate pointers to an already allocated memory space. What would happen if I call arr[0][0][0] = (int*)malloc(2*2*3*4*sizeof(int)); at some point, after using your code to set up the indices?

12. Originally Posted by itsme86
Well I'm still not clear on which parts of the array you want to be contiguous. I don't only have "y" calls to malloc(sizeof(double) * z);. Don't forget that it's in a nested loop so there's actually w*x*y calls to it, which means that the array can hold w*x*y*z doubles, which is what I thought you were looking for.
To me it looks like ShaunMahony is trying to extend the "contiguous" example described here, which has a two-dimensional version done like this.
You can keep the array's contents contiguous, while making later reallocation of individual rows difficult, with a bit of explicit pointer arithmetic:
Code:
```    int **array2 = (int **)malloc(nrows * sizeof(int *));
array2[0] = (int *)malloc(nrows * ncolumns * sizeof(int));
for(i = 1; i < nrows; i++)
array2[i] = array2[0] + i * ncolumns;```
In either case, the elements of the dynamic array can be accessed with normal-looking array subscripts: arrayx[i][j] (for 0 <= i < NROWS and 0 <= j < NCOLUMNS).

13. Hello,

» One question though; is the data gauranteed to be contiguous.
Well, I'm not exactly sure what you are referring too. C provides calloc() ("contiguous allocation") and malloc() ("memory allocation") in the standard library for dynamic memory allocation. For example:
Code:
```#include <stdlib.h>

int main() {
int *a = NULL, n = 5;

a = calloc(n, sizeof(int)); /* get space for n ints */
/* is equivilent to: */
/* a = malloc(n * sizeof(int)); */

free(a);

return 0;
}```
Looking at Dave_Sinkula's post, I think I understand now. The way things look, my code isn't contiguous.

» What does "sizeof *arr" return?
Quite simple. sizeof(int) returns the size of an integer on the machine. My malloc functions as it sends what arr is pointing to, which is an int.

» Where is the actual dataspace being allocated though?
Simply. This is how my concept works.
• Allocate arr[i] as i represents arr[2][2][3][4]
• If allocation succeeds; Loop twice (i < 2) to allocate arr[i][j] as j represents arr[2][2][3][4]
• Per loop (which loops twice) loop 2 times (j < 2) to allocate arr[i][j][k] as k represents arr[2][2][3][4]
• Per loop inside i and j loop 3 times (k < 3) to allocate arr[i][j][k][l] as l represents arr[2][2][3][[b]4/b]]
It may seem a bit complicated, but the idea is a logical one to me.

- Stack Overflow

14. Is this what you're after?

bar is the simple case, which should be easy to understand, and shows how the process starts.
foo is the expanded to 4D case.

Code:
```#include <stdio.h>
#include <stdlib.h>

void *my_malloc ( char *expr, size_t size ) {
void *result = malloc( size );
printf( "Malloc(%s) is size %lu, returning %p\n", expr, (unsigned long)size, result );
return result;
}
void my_free( void *ptr ) {
printf( "Free(%p)\n", ptr );
free( ptr );
}
#define MY_MALLOC(x)    my_malloc( #x, x )
#define MY_FREE(x)      my_free(x)

/* create int [x][y] */
int **create_a_bar ( int max_x, int max_y ) {
int **all_x = MY_MALLOC( max_x * sizeof *all_x );
int  *all_y = MY_MALLOC( max_x * max_y * sizeof *all_y );
int **result = all_x;
int x;

for ( x = 0 ; x < max_x ; x++, all_y += max_y ) {
result[x] = all_y;
}

return result;
}

/* create int [x][y][r][c] */
int ****create_a_foo ( int max_x, int max_y, int max_r, int max_c ) {
int ****all_x = MY_MALLOC( max_x * sizeof *all_x );
int  ***all_y = MY_MALLOC( max_x * max_y * sizeof *all_y );
int   **all_r = MY_MALLOC( max_x * max_y * max_r * sizeof *all_r );
int    *all_c = MY_MALLOC( max_x * max_y * max_r * max_c * sizeof *all_c );
int ****result = all_x;
int x, y, r;

for ( x = 0 ; x < max_x ; x++, all_y += max_y ) {
result[x] = all_y;
for ( y = 0 ; y < max_y ; y++, all_r += max_r ) {
result[x][y] = all_r;
for ( r = 0 ; r < max_r ; r++, all_c += max_c ) {
result[x][y][r] = all_c;
}
}
}

return result;
}

int main ( ) {
int ****foo;
int **bar;
int x,y;

printf( "Creating bar(2,3)\n" );
bar = create_a_bar(2,3);
printf( "Creating foo(2,3,4,5)\n" );
foo = create_a_foo(2,3,4,5);

printf( "\nContiguous memory check\n" );
for ( x = 0 ; x < 2 ; x++ ) {
for ( y = 0 ; y < 3 ; y++ ) {
printf( "%p ", &bar[x][y] );
}
printf( "\n" );
}
printf( "\n" );

printf( "Freeing bar\n" );
MY_FREE( bar[0] );
MY_FREE( bar );
printf( "Freeing foo\n" );
MY_FREE( foo[0][0][0] );
MY_FREE( foo[0][0] );
MY_FREE( foo[0] );
MY_FREE( foo );

return 0;
}```

15. > Well, I'm not exactly sure what you are referring too. C provides calloc() ("contiguous allocation")
calloc means cleared, not contiguous. calloc is just malloc and a memset - nothing more.

Each call to malloc is guaranteed to return a pointer to a block of contiguous memory of the size specified, or NULL if there is a problem.

Page 1 of 2 12 Last