tags:

views:

399

answers:

4

In C, I want to loop through an array in this order

 for(int z = 0; z < NZ; z++)
    for(int x = 0; x < NX; x++)
       for(int y = 0; y < NY; y++)
           3Darray[x][y][z] = 100;

How do I create this array in such a way that 3Darray[0][1][0] comes right before 3Darray[0][2][0] in memory?

I can get an initialization to work that gives me "z-major" ordering, but I really want a y-major ordering for this 3d array

This is the code I have been trying to use:

char *space;
char ***Arr3D;
int y, z;
ptrdiff_t diff;



space = malloc(X_DIM * Y_DIM * Z_DIM * sizeof(char))

Arr3D = malloc(Z_DIM * sizeof(char **));

for (z = 0; z < Z_DIM; z++)
{
    Arr3D[z] = malloc(Y_DIM * sizeof(char *));

    for (y = 0; y < Y_DIM; y++)
    {
        Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
    }
}
+5  A: 

You can't change the array ordering implicit in the language. The array ordering is standard in C.

If you want to change the way your ordering occurs, just change how you access your array, ie: [x][z][y] instead of [x][y][z].

Reed Copsey
Are you certain on this? I suspected this was the case, but I never could find out why. I am dynamically creating the array with malloc and using an offset. I have edited the original post to show code I have been trying to use
Derek
Note: i have tried switching some of the dimensions around in that code, but it more or less is coming out the same ordering every time
Derek
@Derek: C **always** uses row-major ordering for multidimensional arrays. Fortran (and matlab) use column-major. This is part of the C spec. See: http://en.wikipedia.org/wiki/Row-major_order
Reed Copsey
@Reed Copsey, I dont think it will work since the unwind of a three dimensional array would be [XYZ][XYZ][XYZ] and the requester wants the Y values to be contiguous.
GrayWizardx
You can always wrap the array accesses in a macro so that `A(a,x,y,z)` expands to `a[x][z][y]`.
caf
By the way, the reason *why* this is a limitation is that the `[]` operator associates left-to-right, so the rightmost `[]` always associates last.
caf
+1  A: 

I think the only way to do this is to write your own wind/unwind functionality on a contiguous datastore. In other words you are going to have to write your own map to calculate the storage position of your values.

If you are trying to make a certain order traversal of your array more efficient, you could always transform the incoming matrix before you put it into the array and then do the transform again when you get it out. C style multi-dimensional arrays are packed order, so the math might get a bit tricky (and is beyond what I can detail out here in the time I have).

Sorry for not having a better answer, but I hope that helps

GrayWizardx
Yeah, I am actually trying to avoid that, because I am working on some memory allocation problems for code that was not written by me. re-writing the code to use that pointer arithmetic is not exactly an option for the end user who gets the code back and wants to use the bracketed syntax
Derek
+1  A: 

Using an array of pointers can speed things up, but at the cost of greater complexity. If you're not certain you need the performance, then you might try using a C macro:

#define ARR3D(x,y,z) space[(x) + XDIM*((y) + Y_DIM*(z))]

This assumes that x, y, and z are the innermost, middle, and outermost dimensions, respectively.

Steve Emmerson
Unless my understanding is wrong, that is what is going on with the arr3d posted in the sample code above. I have tried switching the dimensions around for the values assigned in the array of pointers without much luck
Derek
A: 

Pseudocode:

malloc a chunk of memory big enough for
   the char *** pointer for z,
   the char ** pointers for y, which will get pointed to by zs
   the char * pointers for x, which will get pointed to by ys
   the big block of data that they will, in the end, be pointed to by xs
assign z's, y's, x's so that 
    contiguous blocks from the big block of data are adjacent in the y dimension
    (instead of adjacent in the x dimension, as would be normal)

I have done the single-malloc trick for 2D arrays, simply because of the mental exercise and the added convenience of a single malloc / single free, and it works beautifully (just make sure to get a well-aligned memory chunk). I never thought of using this to subvert memory adjacency.

tucuxi