tags:

views:

144

answers:

3

For a 4-D array, I'm trying to average the values using compact pointer notation. Using examples from my text, it says I can use something like this:

void DisplayAverage(double (*set)[DIM1][DIM2][DIM3])
    double *ptr;
double subTotal2 = 0; 
    for (ptr = (double *)set; ptr < (double *)set + DIM0 * DIM1 * DIM2 * DIM3; ptr++) {
    subTotal2 += *ptr;
    subTotal2 /= (DIM0 * DIM1 * DIM2 * DIM3); 
cout << "Using compact pointer operations, total: " << subTotal2 << "\n";
    }
}

That code works. However, if I try to use another notation from the text:

for (ptr = (double *)set; ptr < (double *)(&set + 1); ptr++) {

to access the array, I get no output. Any thoughts? Thanks.

+2  A: 

You have one address-of too much:

// notice: "set" instead of "&set"
for (ptr = (double *)set; ptr < (double *)(set + DIM0); ptr++) {

You were adding one to the address of your parameter (and thus were pointing to nowhereland), instead of DIM0 to the value of your parameter (which will bring you to after the array data, which is your goal).

Notice that the parameter is a pointer to an array of dimensions [DIM1][DIM2][DIM3]. In other words, the argument you pass to the function can be an array of type double[DIM0][DIM1][DIM2][DIM3], which will decay to the pointer type of that parameter. You have DIM0 rows, so you add DIM0 to that pointer to reach the position after the last cell.

What you were probably having in mind was adding one to the pointer to the whole array. This will work if you have the following declaration, instead.

void DisplayAverage(double (*set)[DIM0][DIM1][DIM2][DIM3]);

You now need to pass the argument using &arg instead of just arg, to actually pass the address of the array, instead of letting it decay to its inner dimension type. The loop can then be written as

for (ptr = (double *)set; ptr < (double *)(set + 1); ptr++) {
Johannes Schaub - litb
A: 

I would recommend against using static multidimensional arrays in C++. See my response in http://stackoverflow.com/questions/2178909/how-to-initialize-3d-array-in-c/2179035#2179035

Tronic
+1  A: 

Your expression (&set + 1) would point to one-past the array if set was an array, but it's not. The variable set is a pointer in disguise (not an array), as are all arrays that look like they were passed by value.

Better example of this:

void g(int a[3]);
// exactly the same as:
void g(int* a);
// note the 3 is ignored by the compiler here! it serves as documentation when
// reading the code, but nothing else, and for this reason you should pretty much
// always drop it, preferring:
void g(int a[]); /*or*/ void g(int* a); // (which are also identical)

void f() {
  int a[3] = {0, 1, 2};
  int* end = (int*)(&a + 1); // &a has type int (*)[3] (that's pointer to array
  // of 3 ints so &a + 1 has the same value as &a[2] + 1 ("one past" the last
  // valid item in a)

  int* p = a; // this is how a is passed "by value" to a function such as g
  end = (int*)(&p + 1); // even though this "looks" the same, &p has type int**
  // and adding 1 to that has no correlation with what p points to.
  // to make matters worse, the cast (and C++-style casts have the same problem
  // here) hides this type error and makes the compiler believe we know what
  // we're doing

  // pointers are not arrays, even though they mostly behave similarly:
  std::cout << sizeof(a) << ", " << sizeof(p) << ", " << sizeof(void*) << '\n';
  // compare the int* size to void* size
}

And example applying it to pointers-to-arrays:

typedef int T[3];
void g(T a[3]);
// same as:
void g(T a[]); /*and*/ void g(T* a);

// that T happens to be an array type doesn't change anything, these are
// also declaring the same function:
void g(int a[][3]); /*and*/ void g(int (*a)[3]);

void f() {
  int a[3][3] = {};
  int* end = (int*)(&a + 1);
  // note that end - &a[0][0] is 9

  int* p = &a[0][0];

  std::cout << sizeof(a) << ", " << sizeof(p) << ", " << sizeof(void*) << '\n';
}
Roger Pate