tags:

views:

215

answers:

4

What is the best way to pass three dimensional arrays into functions in C?

+3  A: 

Pass them as pointers.

Example

int a[N][M][P];

foo( &a[0][0][0]);

where foo is

void foo( int*)

You might need to pass the dimensions as well, so in such case you might need:

void foo( int*, int D1, int D2, int D3)

and call

foo( &a[0][0][0], N, M, P);
Cătălin Pitiș
Is the [0][0][0] necessary there?
Cory Petosky
@Cory, yes it first gets at the first int, and takes it address. That gives the resulting expression type `int*` instead of array pointer like `int(*)[N][M][P]`. This is a good hack in my opinion, it can improve program clarity by not having to deal with constants everywhere. But it's formally not guaranteed to work, so use it with care (not sure what could go wrong though).
Johannes Schaub - litb
Johannes Schaub - litb
+4  A: 

It is required you have all but the left-most dimension to be defined at compile time.

#define DIM 5

void do_something(float array[][DIM][DIM])
{
    array[0][0][0] = 0;
    ...
}
Didier Trosset
+5  A: 

typedef is your friend.

#include <stdio.h>
typedef int dimension1[20]; /* define dimension1 as array of 20
                               elements of type int */
typedef dimension1 dimension2[10]; /* define dimension2 as array of 10
                                      elements of type dimension1 */

int foo(dimension2 arr[], size_t siz);

int main(void) {
  dimension2 dimension3[7] = {0}; /* declare dimension3 as an array of 7
                                     elements of type dimension2 */
  dimension3[4][3][2] = 9999;
  dimension3[4][0][12] = 1;
  dimension3[3][8][18] = 42;

  printf("%d\n", foo(dimension3, 7));

  return 0;
}

int foo(dimension2 arr[], size_t siz) {
  int d1, d2, d3;
  int retval = 0;
  for (d3=0; d3<siz; d3++) {
    for (d2=0; d2<sizeof *arr / sizeof **arr; d2++) {
      for (d1=0; d1<sizeof **arr / sizeof ***arr; d1++) {
        retval += arr[d3][d2][d1];
      }
    }
    /* edit: previous answer used definite types for the sizeof argument */
    //for (d2=0; d2<sizeof (dimension2) / sizeof (dimension1); d2++) {
    //  for (d1=0; d1<sizeof (dimension1) / sizeof (int); d1++) {
    //    retval += arr[d3][d2][d1];
    //  }
    //}
  }
  return retval;
}


Edit

I don't like the use of definite types as the argument to sizeof.
I added the way to get the sizes of the (sub-)arrays without directly specifying their types, but rather let the compiler infer the right type from the object definitions.


2nd Edit

As Per Eckman notes typedef-ing "bare" arrays can be dangerous. Note that in the code above, I'm not passing arrays themselves to the function foo. I am passing a pointer to a "lower level" array.

foo(), in the code above, accepts a pointer to an object of type dimension2. The dimension3 object is an array of elements of dimension2 type, not an object of dimension3 type (which isn't even defined).

But remember Per Eckman's note.

pmg
+1  A: 

typedef-ing "bare" arrays can be dangerous.

Try this

#include <stdio.h>

typedef char t1[10];

void foo(t1 a) {
        t1 b;

        printf("%d %d\n", sizeof a, sizeof b);
}

int main(void) {
        t1 a;
        foo(a);
        return 0;
}

One would think that sizeof two variables of the same type would return the same size but not in this case. For this reason it's a good practice to wrap typedef-ed arrays in a struct.

typedef struct {
        char x[10];
} t1;
Per Ekman
+1 Very good reminder
pmg