0

Im writing a little thing involving voxels, so I have a 3d array filled with data, like this

typedef struct data{float m,vx,vy,vz;} data;
data pool[2][x][y][z];
data voronoi[26];

where x, y and z are uint64_t. But their actual value depends on user input during runtime. Now it turns out that I get a segmentation fault when the array gets too big (can't even do 128x128x128), even though I have more than enough RAM. So I need to allocate it on the heap. How do I do this, while also not needing to convert code like this:

uint64_t h,b,d,p;
p = 0;
for(h=1;h<y-1;++h){
for(b=1;b<x-1;++b){
for(d=1;d<z-1;++d){
voronoi[ 0] = pool[p][h-1][b-1][d-1];
voronoi[ 1] = pool[p][h  ][b-1][d-1];
voronoi[ 2] = pool[p][h+1][b-1][d-1];
voronoi[ 3] = pool[p][h-1][b  ][d-1];
voronoi[ 4] = pool[p][h  ][b  ][d-1];
voronoi[ 5] = pool[p][h+1][b  ][d-1];
voronoi[ 6] = pool[p][h-1][b+1][d-1];
voronoi[ 7] = pool[p][h  ][b+1][d-1];
voronoi[ 8] = pool[p][h+1][b+1][d-1];
    //etc until 26

}}}
p = 1;
// repeat cycle, then p=0 again, etc

Simply mallocing pool like so:

data* pool=(2*x*y*z*sizeof(data));

This is not a duplicate, because malloc-ing a 1d array and adding custom indexing (the goto answer) invalidates the multidimensional square bracket indexing syntax.

trincot
  • 317,000
  • 35
  • 244
  • 286

1 Answers1

3

Simple. Use a pointer to a multidimensional array:

data (*pool)[x][y][z] = malloc(2*sizeof(*pool));
...
for(h=1;h<y-1;++h){
    for(b=1;b<x-1;++b){
        for(d=1;d<z-1;++d){
            voronoi[ 0] = pool[p][h-1][b-1][d-1];
            ...
}
...
free(pool);

Note that the outermost dimension 2 is a factor within the malloc() argument, the other dimensions are part of the pointer type and sizeof(*pool) correctly computes the size of one 3D slice of your 4D array.

The dimensions x, y, z do not need to be compile time constants. They can by function arguments, local variables, struct members, whatever. Their value just has to be known at the declaration of the pointer.

This works in C since C99, but it does not work in C++ of any standard. C11 made this feature optional to make it easier to implement a conforming compiler for new platforms, but the big compiler suites offer full support of this feature.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • 1
    And annoyingly, the `__STDC_NO_VLA__` macro doesn't exist under C99, so it can't easily be used to reliably detect support/non-support of VLAs. Thanks Microsoft. :-/ – Andrew Henle Feb 04 '20 at 12:13