EssentialAnonymity
EssentialAnonymity

Reputation: 316

C Dynamic 3D array memory

I have the following code to dynamically create 2D arrays. For my application, I need to have the data stored contiguously.

I would like to generalize the 2D code below to 3D arrays. How can I do this?

double *psiMemLoc;
double **psi;

  psiMemLoc = malloc(sizeof(double)*(lasty-firsty+3)*(lastx-firstx+3));
  psi = malloc(sizeof(double *) * (lasty-firsty+3));
  for(j=firsty-1; j<=lasty+1; j++){
    psi[j] = psiMemLoc + (lastx-firstx+3)*j;
  }

With the above code, I can access elements of psi like psi[j][i]. To reiterate my goal, I would like to generate a 3D array that I can access using psi[k][j][i].

To give some context, I am solving a 2D PDE and the third dimension will be used to store a few of the previous timestep solutions. So the number of memory locations between timesteps should be (lasty-firsty+3)*(lastx-firstx+3).

Thank you!

Upvotes: 0

Views: 79

Answers (3)

user2736738
user2736738

Reputation: 30926

You can get 3d contiguous allocated memory like this

double (*a)[sz][sz]= malloc(sizeof *a *sz);
if( a == NULL){
   // error in malloc
   exit(1);
}

This is a bit different than what you did. But it will serve your purpose.

  for(size_t i=0;i<sz;i++)
    for(size_t j=0;j<sz;j++)
      for(size_t k=0;k<sz;k++)
         // access a[i][j][k]

Freeing will be simply a call like this free(a). (When you are done working with it free the memory).

Note: This will work for C99 and onwards. In addition to that C11 made VLA's optional that breaks the guarantee. But as an way out you can always allocate the whole chunk and access them accordingly.


The other way to go about it would be to use jagged array (not contiguous memory).

double ***a;

Now in some function you do this

a = malloc(sizeof *a* sz1);
if( a == NULL ){
   // ..
}
for(size_t i = 0; i<sz1; i++){
 a[i]= malloc(sizeof *a[i]*sz2);
 if( !a[i] ){
   for(size_t j = 0; j<sz2; j++)
     a[i][j]=malloc(sizeof *a[i][j]*sz3);
     if( a[i][j] == NULL){
      //error
     }
 }
 else
   // error
}
//If you have an jagged array a[sz1][sz2][sz3];

Upvotes: 3

user2371524
user2371524

Reputation:

This is meant as a supplementary answer: The correct way to allocate a multidimensional array with malloc() is indeed using VLA syntax, as shown in coderredoc's answer. Unfortunately, C11 doesn't require a conforming implementation to support VLAs any more. While this should almost never be an issue in practice, it's still worth noting that you can do the same explicitly in code without using VLAs:

int x = 5;
int y = 10;
int z = 3;

double *array3d = malloc(x*y*z * sizeof *array3d);

// access to [3][2][1]:
array3d[3*y*z + 2*z + 1]

Although that's not really a 3d array, it has the same memory representation (contiguous) and you just do the index calculation explicitly that would otherwise be generated by the compiler.

As the code is less readable, always prefer the syntax shown in the other answer if you can (-> if your compiler supports VLAs and there's no reason to assume it's ever compiled with one that doesn't).

Upvotes: 1

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9203

That doesn't look like a 2D/3D array at all.

What you have created is an array of pointers each of which point inside a contiguous block of memory. Although this might give a feel of pointers, the correct way to make a 2D array would be -

double (*array_2d)[lastx-firstx+3] = malloc(sizeof (*array_2d) * (lasty-firsty+3));

Similarily a 3D array can be made as -

double (*array_3d)[X][Y] = malloc(sizeof(*array_3d) * Z);

Upvotes: 0

Related Questions