Конец многомерного массива с использованием компактной записи указателя - PullRequest
0 голосов
/ 04 февраля 2010

Для 4-D массива я пытаюсь усреднить значения, используя компактную запись указателя.Используя примеры из моего текста, он говорит, что я могу использовать что-то вроде этого:

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";
    }
}

Этот код работает.Однако, если я попытаюсь использовать другую запись из текста:

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

для доступа к массиву, я не получу вывод.Какие-нибудь мысли?Спасибо.

Ответы [ 3 ]

2 голосов
/ 04 февраля 2010

У вас есть один адрес - слишком много:

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

Вы добавляли единицу к адресу вашего параметра (и, следовательно, указывали на нигде), а не DIM0 к значению вашего параметра (который приведет вас к данным массива, что является вашей целью).

Обратите внимание, что параметр является указателем на массив измерений [DIM1][DIM2][DIM3]. Другими словами, аргумент, передаваемый функции, может быть массивом типа double[DIM0][DIM1][DIM2][DIM3], который будет переходить в тип указателя этого параметра. У вас есть DIM0 строк, поэтому вы добавляете DIM0 к этому указателю, чтобы достичь позиции после последней ячейки.

То, что вы, вероятно, имели в виду, это добавление единицы к указателю на весь массив. Это будет работать, если у вас есть следующее объявление.

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

Теперь вам нужно передать аргумент, используя &arg вместо просто arg, чтобы фактически передать адрес массива вместо того, чтобы позволить ему распадаться на тип внутреннего измерения. Цикл может быть записан как

for (ptr = (double *)set; ptr < (double *)(set + 1); ptr++) {
1 голос
/ 04 февраля 2010

Ваше выражение (&set + 1) будет указывать на один конец массива, если set был массивом, но это , а не . Переменная set является скрытым указателем (не массивом), как и все массивы, которые выглядят так, как будто они были переданы по значению.

Лучший пример этого:

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
}

И пример применения его к указателям на массивы:

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';
}
0 голосов
/ 04 февраля 2010

Я бы рекомендовал не использовать статические многомерные массивы в C ++. Смотрите мой ответ в Как инициализировать 3D-массив в C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...