0

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!

3 Answers 3

3

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];
Sign up to request clarification or add additional context in comments.

7 Comments

Worth mentioning it's a C99 and onward thing, just in case the OP comes back with a question about error messages. Other than that, well suggested.
In fact, it requires VLAs, they're not guaranteed any more by C11. Should be mentioned, still it's the recommended thing to do. Short of VLAs, you can only allocate a flattened array and calculate the indices explicitly in code.
@EternusVia.: If I am not getting you wrong,I suppose you want to declare the array global so that you can access it easily from other functions.(not a good practice,not recommended)but AFAIK you can do this thing-declare the variable.Then inmain()whenever you get to know about the size of the array,call a function which will allocate memory in that global variable.And then do all the work and free it after work. Yes this you can do. But better when you get time, try to pass the array across functions (one method for allocating, one or more for the main work, and then freeing the resource).
@EternusVia.: Now look. Here you have to do something a bit more stricter than you would expect it to be. For example, you have keep this part double (*a)[MAXSIZE][MAXSIZE] and then one of the part you can allocate. If you are not feeling well to do that then you have either the jagged array solution. Which will be something like this stackoverflow.com/questions/47398202/… ..which is precisely the solution you may use completely globally.
@EternusVia.: I have given you the solution here also for 3d array so that you can understand what is to be done here.
|
1

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).

Comments

0

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.