I am working with a very large 5D array that I need to read into contiguous memory (another 5D array). I cannot place the array on the stack because it is too large and creates seg faults. What I've done is to create a 5D array dynamically with malloc however I've found that it is not contiguous memory. Is there an elegant solution to this or is it going to be messy no matter what?
-
Show the relevant code. – Nelfeal Sep 02 '16 at 18:25
-
It gets messy, see e.g.: http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ – deamentiaemundi Sep 02 '16 at 18:25
-
@Nelxiost , stand by for that. When I get home I will post it. – LTClipp Sep 02 '16 at 18:28
-
1instead of making your variable a 5d array, make it a pointer to 5d array, then malloc memory to that pointer. in this case, an array can be allocated just like any other object – user3528438 Sep 02 '16 at 18:30
-
2possibly duplicate [How do I work with dynamic multi-dimensional arrays in C?](http://stackoverflow.com/questions/917783/how-do-i-work-with-dynamic-multi-dimensional-arrays-in-c) – Rebecca Joanna Sep 02 '16 at 18:39
-
2You know that a 5d array is simply a design error, don't you? Unless it represents an actual mathematical object as such, tensors come to mind. But still, thinking of an array like that seems a problem in understanding the underlying problem that you are attempting to solve. – Iharob Al Asimi Sep 02 '16 at 18:59
-
Also, `x[0][0][0][0][0]` is already messy. – Iharob Al Asimi Sep 02 '16 at 19:02
-
@iharob I am working with a scientific data set where each dimension represents things like different pixels, different channels, calibration data etc, and this dataset is 5 dimensions. – LTClipp Sep 02 '16 at 19:09
-
The reason you need to show your code is "*We don't know how you have declared or filled your 5D array?*". For all we know you have created it as a *pointer to pointer to pointer to pointer to pointer to type*, which is not an array and not equivalent to `a[a][b][c][d][e]`. If it is a real array, you can create a pointer to a 5D array with `type (*p)[a][b][c][d][e] = NULL;` and then `p = malloc (sizeof array_orig);` then `memcpy (p, array_orig, sizeof array_orig);` But, without your code, there is no way of knowing for sure. – David C. Rankin Sep 02 '16 at 19:39
-
Although [How do I work with dynamic multi-dimensional arrays in C?](http://stackoverflow.com/questions/917783/how-do-i-work-with-dynamic-multi-dimensional-arrays-in-c) is certainly closely related, none of the answers there encroaches on 5D arrays — 3D arrays get mentioned in passing. And the (pointer to) VLA (variable length array) approach that is probably desired isn't spelled out in detail in the answers. – Jonathan Leffler Sep 02 '16 at 19:41
-
I presume you have _dynamic_ array dimensions (e.g. `int dim3 = ...; int myarray[10][20][dim3][97][64];`). Otherwise, if the dimensions are fixed, it would just be a global (e.g. `int myarray[10][20][37][97][64]`). And, you don't know the dimensions until some code is run (e.g. in `main`, `dim3 = atoi(argv[3]);` So, we really need some of the code you have, to narrow down to the best alternate solutions. – Craig Estey Sep 02 '16 at 19:47
-
You need, a struct it can't be more clear. `struct data {channel_type channel; pixel_type pixel; ... }` and so on. – Iharob Al Asimi Sep 02 '16 at 21:14
-
@iharob sorry dude but no, I cannot use a struct. It doesn't apply to what I'm trying to do. I could go on for a long time explaining why I can't but I'm telling you that these are the constraints I'm dealing with. Structs do not solve my problem. – LTClipp Sep 02 '16 at 22:05
6 Answers
From Jens Gustedt: Don't use fake matrices.
Allocate a 5-dimensional matrix with dimensions A x B x C x D x E (dimensions aren't required to be known at compile time) like so:
float (*matrix5d)[B][C][D][E] = malloc(sizeof(float[A][B][C][D][E]));
Release the memory with a single call to free.
free(matrix5d);
Note that the above requires C99 or higher for variable-length arrays.

- 1,644
- 1
- 17
- 29
-
How do I access the offsets? For operation `matrix[i][0] = i;` I get ` error: incompatible types when assigning to type 'int[(sizetype)s2_len + 1u]' from type 'size_t'` when matrix is defined as `int (*matrix)[s1_len+1][s2_len+1]`. – Tomáš Zato Nov 28 '16 at 20:28
-
1Strictly, it requires a C99 implementation (all C99 implementations are required to support VLAs) or a C11 implementation that does not define `__STDC_NO_VLA__` (since VLA support is optional in C11). – Jonathan Leffler Nov 28 '16 at 20:34
-
@TomášZato You need the third index to do an assignment: `matrix[i][0][0] = i`. – thndrwrks Nov 28 '16 at 20:57
-
@thndrwrks Thanks for reply. I used `(*matrix)[i][0] = i` instead, I guess that's equivalent. I find it more intuitive. – Tomáš Zato Nov 28 '16 at 20:58
Being represented via a contiguous chunk of memory is one of the distinguishing properties of a C array. Multidimensional arrays are arrays of arrays, and therefore contiguous the same as any other array, so if you want a genuine 5D array then you certainly do need contiguous memory for it. As some of the other answers have observed, to ensure that you get a contiguous block of memory, you must allocate the whole thing at once.
Although you can form data structures consisting of arrays of pointers to [[arrays of pointers to [arrays of pointers to ...]] arrays, these are not the same thing at all, just as pointers are not arrays. You can use the indexing operator, []
, with such data structures in the same way that you can do with multi-dimensional arrays, but that doesn't make them the same thing.
@EvelynParenteau suggested simulating your 5D array with a 1D array, and indeed that's one way to satisfy your contiguity requirement. You could even write macros to make indexing into such an array easier.
But as long as you are using at least C99, you can dynamically allocate a genuine 5D array. The general form might look something like this:
void allocate_5d(unsigned dim1, unsigned dim2, unsigned dim3, unsigned dim4,
unsigned dim5, double (**aptr)[dim2][dim3][dim4][dim5]) {
*aptr = malloc(dim1 * sizeof(**aptr));
}
It would be used like this:
void do_something(unsigned dim1, unsigned dim2, unsigned dim3, unsigned dim4,
unsigned dim5) {
double (*array)[dim2][dim3][dim4][dim5];
allocate_5d(dim1, dim2, dim4, dim4, dim5, &array);
if (!array) {
// Handle allocation failure ...
}
array[0][0][0][0][0] = 42;
// ...
free(array);
}
If dimensions 2 - 5 are compile-time constants, then you can even do a this (slightly differently) in C90, but the variation presented above depends on variable-length arrays, which were new in C99.

- 160,171
- 8
- 81
- 157
One way of thinking about it is to use malloc
to allocate a 1d array of 4d arrays, because fundamentally malloc
can only allocate 1d arrays, and an N-d array is just 1d array of (N-1)-d arrays.
However, just like any array allocated by malloc
, the "array object" is actually a pointer, so you shouldn't use sizeof()
to get the size of the array.
#include <stdio.h>
#include <stdlib.h>
typedef int Array_4D_Type[4][3][2][1];
int main(void) {
Array_4D_Type *arr = malloc(5 * sizeof(Array_4D_Type));
// ^^^^^^^^^^^^^^^^ here, allocate a length-5 vector of 4d array type
int *p = &arr[0][0][0][0][0];
for (int i = 0 ; i < 120 ; i++){
p[i] = i;
}
printf("arr_start = %d, end = %d\n", arr[0][0][0][0][0], arr[4][3][2][1][0]);
return 0;
}
Update:
As is mentioned in the comments, using typedef
here forces the array to be static sized except the top dimension.
The use of typedef
here is only to make the pointer-to-array syntax a little cleaner.
However, with VLA enabled, int (*arr)[n][o][p][q] = malloc(m*sizeof(*arr));
should still work and allow you to specify dynamic size on each dimension.

- 2,737
- 2
- 23
- 42
-
The dimension `[1]` is modestly pointless, of course. More seriously, how can you adapt this code to give a `int arr1[6][5][4][3][2]` and `int arr2[2][3][4][5][6]`? With your typedef, you can only deal with arbitrarily sized arrays of the fixed 4-D array type, rather than arbitrarily sized arrays of arbitrary 4-D array types. – Jonathan Leffler Sep 02 '16 at 19:31
-
@JonathanLeffler `int (*arr)[5][4][3][2] = malloc(6*sizeof(*arr));` http://ideone.com/mjv9GQ As you mentioned `typedef` does require a constant size and I didn't really consider using VLA to get dynamic size done. The reason I picked 4+1 D – user3528438 Sep 02 '16 at 19:46
-
@JonathanLeffler is because I feel it doesn't need the (redundant) top-level deference as in the "pointer to 5d" approach. – user3528438 Sep 02 '16 at 19:54
There is a way to make the memory contiguous, but whether its elegant or messy I'll leave up to you ;)
First, let's consider the case of a 1 dimensional array. In this case, it's trivial to get contiguous memory; the memory you get from malloc
will be contiguous. It seems simple enough, but we're going to later use this fact to get a 5 dimensional contiguous array.
Now, let's consider a 2 dimensional array that is M
by N
in size. Here's one way of creating one (assuming we're using float
s).
float** array2d = malloc(M * sizeof(float*));
for (int i = 0; i < M; i++) {
array2d[i] = malloc(N * sizeof(float));
}
Strictly speaking, this is not a two dimensional array, it's an array of arrays. Now, we can access elements of array2d
like array2d[0][0]
, array2d[0][1]
etc. Conceptually this is very nice, but as you've noted, we don't necessarily have contiguous memory since we did multiple calls to malloc
. What we need is a way to allocate all of the memory necessary to store M*N
floats in one call to malloc
.
float* array2d = malloc(M * N * sizeof(float));
Note that in this form, array2d
is float*
instead of float**
, i.e. it's an array of floats, not an array of arrays of floats. So, we can't do array2d[0][0]
any more. How do we now index this array?
It's entirely up to us to decide how this 2 dimensional array is laid out in memory. Let's say that M
is the "width" of the array (meaning the number of elements in a row) and that N
is the "height" of the array (meaning the number of rows in the array). Also, let's just say that the first M
entries in the array are the first row, the next M
entries are the second row, etc. So to read the entry at row y
, column x
, we would do this:
float data = array2d[y * M + x];
Say we want element (0, 0). Then y * M + x
simply becomes 0, so we're good. Now say we want element (1, 0) (i.e. the first element in the second row). Then, y * M + x
becomes M
, which as we've decided above is where the second row starts.
We can generalize this approach to higher dimensions. Let's say we have a three dimensional array of size L
by M
by N
. You can think of this as L
two dimensional arrays laid out sequentially in memory, all of size M
by N
. Then, to access element (x
, y
, z
) we would do:
float data = array3d[z * (M * N) + y * (M) + x];
Conceptually you can think of this as skipping the first z
two dimensional arrays, then skipping the first y
rows of that array, and then going to the x
th element of that row. For more dimensions, there are more multiplicative terms when indexing, but the approach is fundamentally the same.

- 94
- 3
-
This is largely right, but the first allocation example *does not* allocate a 2D array. An array of pointers is not at all the same thing as a 2D array. – John Bollinger Sep 02 '16 at 19:21
-
Correct. I put the first example there as an example that _wouldn't_ meet the requirements. I'll edit it to make that more clear. – Evelyn Parenteau Sep 02 '16 at 19:49
With dynamic allocation, using malloc:
int** x;
x = malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
x[i] = malloc(dimension2_max * sizeof(int));
}
[...]
for (int i = 0; i < dimension1_max; i++) {
free(x[i]);
}
free(x);
This allocates an 2D array of size dimension1_max * dimension2_max. So, for example, if you want a 640*480 array (f.e. pixels of an image), use dimension1_max = 640, dimension2_max = 480. You can then access the array using x[d1][d2] where d1 = 0..639, d2 = 0..479.
But a search on SO or Google also reveals other possibilities, for example in this SO question
Note that your array won't allocate a contiguous region of memory (640*480 bytes) in that case which could give problems with functions that assume this. So to get the array satisfy the condition, replace the malloc block above with this:
int** x;
int* temp;
x = malloc(dimension1_max * sizeof(int*));
temp = malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
x[i] = temp + (i * dimension2_max);
}
[...]
free(temp);
free(x);
on similar way you can build dynamically 5d array

- 81,885
- 6
- 58
- 85

- 335
- 1
- 14
-
I removed the `snippet` sections, C is not javascript and the snippets don't make sense in the answer. – David C. Rankin Sep 02 '16 at 18:45
-
2***note:*** you can also simply use a dereference of the variable itself with the `sizeof` operator, e.g. `x = malloc(dimension1_max * sizeof *x);` and similarly `x[i] = malloc(dimension2_max * sizeof **x);` (or `*(x[i])`) It prevents ever including an incorrect type with `sizeof`. – David C. Rankin Sep 02 '16 at 18:51
-
What you present *does not* allocate a 2D array, and the data are *not* guaranteed to meet the OP's contiguity requirement. Instead, you are allocating a bunch of separate 1D arrays -- which may or may not be contiguous with each other -- and an array of pointers to those arrays. That's not the same thing at all. – John Bollinger Sep 02 '16 at 19:17
If I understand your question, that you have a current 5D array, and you need to allocate storage for, and make a copy of that array, and then you wish to access the values in a sequential manner. As others have noted, the approach is to use a pointer to a 4D array to allocate a block of memory dim1 * sizeof 4D
to hold your existing array. (you can think about is as allocating for dim1 rows of what makes up your 5D array). You can then simply copy the existing array, (using memcpy
or the like) then and assign a pointer to the first element for sequential access.
The benefit is you allocate a single block to hold a copy of your existing array. This will require only a single free
when you are done making use of the copy.
This does not work with fake (pointer to pointer to pointer... collections of memory)
Below is a short example of creating a dim1
pointers to what makes up the remaining 4d of your existing array (in a single block allocation) where all but your dim1
dimensions are known at compile time. The existing 5D array a
is copied to a new block of memory assigned to b
. An integer pointer 'p' is then assigned the beginning address of b
. The values of b
are accessed sequentially through pointer p
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
int a[2][2][2][2][2] = { { { {{1,2}, {3,4}}, /* 5D Array */
{{5,6}, {7,8}} },
{ {{1,2}, {3,4}},
{{5,6}, {7,8}} } },
{ { {{1,2}, {3,4}},
{{5,6}, {7,8}} },
{ {{1,2}, {3,4}},
{{5,6}, {7,8}} } } };
/* ptr to 5D, ptr to int* */
int (*b)[2][2][2][2] = NULL, *p = NULL;
/* allocate block to hold a */
b = malloc (sizeof a/sizeof *a * sizeof *b);
memcpy (b, a, sizeof a/sizeof *a * sizeof *b); /* copy a to b */
p = ****b; /* assign address of first element */
printf ("\nb:\n"); /* ouput using sequential access */
for (int i = 0; i < (int)(sizeof a/sizeof *****a); i++)
printf (" *(p + %2d) : %d\n", i, p[i]);
free (b); /* single free is all that is required */
return 0;
}
Example Use/Output
$ ./bin/arr5dstatic1
b:
*(p + 0) : 1
*(p + 1) : 2
*(p + 2) : 3
*(p + 3) : 4
*(p + 4) : 5
*(p + 5) : 6
*(p + 6) : 7
*(p + 7) : 8
*(p + 8) : 1
*(p + 9) : 2
*(p + 10) : 3
*(p + 11) : 4
*(p + 12) : 5
*(p + 13) : 6
*(p + 14) : 7
*(p + 15) : 8
*(p + 16) : 1
*(p + 17) : 2
*(p + 18) : 3
*(p + 19) : 4
*(p + 20) : 5
*(p + 21) : 6
*(p + 22) : 7
*(p + 23) : 8
*(p + 24) : 1
*(p + 25) : 2
*(p + 26) : 3
*(p + 27) : 4
*(p + 28) : 5
*(p + 29) : 6
*(p + 30) : 7
*(p + 31) : 8
There is good reason that the rest of the comments and answers suggest you find some way other than using a 5D array setup. It would be worth while to investigate if you can modify whatever is producing the data you capture in your original 5D array to output the data in some other format.

- 81,885
- 6
- 58
- 85