0

I need to build two 3D contiguous arrays in C (noted x0 and x). The dimensions must be x[size_tot_y][size_tot_x][size_tot_z] and x0[size_tot_y][size_tot_x][size_tot_z] .Here's my code :

  double*** x;
  double** x_val2;

  double*** x0;
  double** x0_val2;

  x0 = malloc(size_tot_y*sizeof(double**));
  x0_val2 = malloc(size_tot_x*size_tot_y*size_tot_z*sizeof(double*));

  x = malloc(size_tot_y*sizeof(double**));
  x_val2 = malloc(size_tot_x*size_tot_y*size_tot_z*sizeof(double*));

  for(j=0;j<=size_tot_y-1;j++) {    
      x0[j] = &x0_val2[j*size_tot_x*size_tot_z];
      x[j] = &x_val2[j*size_tot_x*size_tot_z];
      }

  for(i=0;i<=size_tot_y-1;i++) {
      for(j=0;j<=size_tot_x-1;j++) {
          x0[i][j] = malloc(size_tot_z*sizeof(double));
      x[i][j] = malloc(size_tot_z*sizeof(double));
      }
     }

  for(i=0;i<=size_tot_y-1;i++) {
      for(j=0;j<=size_tot_x-1;j++) {
          x0[i][j] = x0_val2[i*j*size_tot_z];
      x[i][j] = x_val2[i*j*size_tot_z];
      }
     }     

Could you see where's the error ?

Thanks

4
  • 4
    You are a 3-star programmer. Commented Oct 4, 2012 at 21:26
  • If by any means you can get hand on a C99 compliant compiler, try to get rid of 3D-array emulation and use pointers to variable length arrays instead. Use something like double (*A)[n][m] = sizeof(double[k][n][m]) and forget about all this pointer-to-pointe-to-pointer stuff. Commented Oct 4, 2012 at 21:36
  • Arrays are not pointers. Arrays are not pointers. You're trying to make pointer-to-pointer-to-pointers, which are different from 3D arrays. Commented Oct 4, 2012 at 21:46
  • What do you mean by contiguous? The moment you use malloc more than once this property is lost. You seem to be specifying contradictory requirements. Can you clarify? Commented Oct 5, 2012 at 11:20

3 Answers 3

1

Your code seems way too complicated to me. Just do:

 double ***x;
 x = malloc(size_tot_y * sizeof(*x));
 for (i = 0; i < size_tot_y; i++) {
   x[i] = malloc(size_tot_x * sizeof(**x));
   for (j = 0; j < size_tot_x; j++) {
     x[i][j] = malloc(size_tot_z * sizeof(***x));
   }
 }

Same for x0. Wrap it in a routine so you don't need to write the same code twice.

Edit

for contiguous array, do:

 double *storage = malloc(size_tot_x * size_tot_y * size_tot_z * sizeof(*storage));
 double *alloc = storage;
 double ***x;
 x = malloc(size_tot_y * sizeof(*x));
 for (i = 0; i < size_tot_y; i++) {
   x[i] = malloc(size_tot_x * sizeof(**x));
   for (j = 0; j < size_tot_x; j++) {
     x[i][j] = alloc;
     alloc += size_tot_z;
   }
 }

That's if you really want the pointers. If not, just allocate all the memory and do the indexing yourself:

double *storage = malloc(size_tot_x * size_tot_y * size_tot_z * sizeof(*storage));
double get(const double *storage, int x, int y, int z) {
    return storage[(y * size_tot_x + x) * size_tot_z + z];
}
Sign up to request clarification or add additional context in comments.

3 Comments

The innermost dimension should be size_tot_z.
That doesn't give a contiguous block of memory. Whether that's a real problem depends.
I need 3d contiguous array for MPI code where I exchange 2d arrays between processes. For that, I use MPI_Sendrecv routines. @Keith, your solution doesn't seem to work.
0

I need 3d contiguous array for MPI code where I exchange 2d arrays between processes. For that, I use MPI_Sendrecv routines which requires contiguous arrays.

@Keith, your solution doesn't seem to work.

For example, in the 2D version of this code, I create 2D contiguous array x0 this way :

  x0 = malloc(size_tot_y*sizeof(double*));
  x0_vals = malloc(size_tot_x*size_tot_y*sizeof(double));

  for(j=0;j<=size_tot_y-1;j++) {
    x0[j] = &x0_vals[j*size_tot_x];
  }

What is the equivalent for 3D ?

Comments

0

I just started C almost a year ago and you're not helping this guy one bit.

I also wanted to use contiguous blocks of memory to make tensors, which are weird multidimensional objects. Think of three 3x3 matrices printed on 3 ortho faces of a cube.

A big problem in C is that when you make a 3D array, arr[number][column][row], which would be "number" of "column x row" matrices, the block of memory contiguous but it is not well ordered.

Have you ever wondered why you initialize an array of say arr[2][4][4]

int arr[2][4][4]=   
        {
            {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 16}
            },
            {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 16}
            },
        };

But we all know that C starts counting at zero, so we have our matrix embedded in a larger matrix with garbage data surrounding it, and a third matrix completely of garbage data. Here's how I printed the garbage data:

#define COMPLEX 2
#define ROW 2
#define COLUMN 2
void L_print(int u[COMPLEX][ROW][COLUMN])
{
    int i,j,k;
    for(i=0;i<=COMPLEX;i++)
    {
        for(j=0;j<=ROW;j++)
        {
            for(k=0;k<=COLUMN;k++)
            {
                printf("%d ",u[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
}

So you get the correct data embedded in the garbage matrix. C seems to fill the garbage data slots with random garbage data, they're not all '\0' or something neat like that.

So I wanted to use pointers for runtime modifications of the size of the matrix, thus I had to make an isomorphism for my operations based on pointers.

Now when i declare a pointer and point it at the first entry of my matrix:

ptr=&a[0][0][0];

And then I print

 L_ptr_print(ptr,(2*4*4));  

This will spit out the proper matrix entries, which is two 4x4 matrices in this case.

But we all know that arrays start counting at zero, so an array arr[2][4][4] actually has 3*5*5 "slots" that are sizeof(int) big. So let's print the slots!

L_ptr_print(ptr,(3*5*5));

What you will get is the first 32 entries are the properly ordered matrix entries. The next 43 entries are the garbage data that you get when you fully print off the matrix arr[2][4][4].

Thus I have determined that the simplest and most elegant way to make a 3D dynamically allocated contiguous array is not not make it 3D in the first place.

Simply malloc your pointer and have the size equal to the number of array elements. So you would malloc a 32*sizeof(int) pointer:

int* ptr;
ptr=(int*)malloc(32*sizeof(int));

and then populate each element of the array like this or however u want to doit.

for(i=0;i<31;i++)
{
    *(ptr+i)=i+1;
}

This can print off 32 ints and it's only 32*sizeof(int) bytes. This eliminates the need for double and triple pointers.

Or if you already have a matrix you can always just point the single pointer to each block manually, and then you don't have to worry about clearing memory because you pointer doesn't take up memory, the array does, and the pointer points to the array. But then you cannot modify the size of the array at runtime.

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.