Массив указателей на многомерные массивы - PullRequest
4 голосов
/ 28 апреля 2009

У меня есть несколько двумерных массивов, таких как:

int shape1[3][5] =  {1,0,0,
             1,0,0,
             1,0,0,
             1,0,0,
             1,0,0};
int shape2[3][5] =  {0,0,0,
             0,0,0,
             0,1,1,
             1,1,0,
             0,1,0};

и т. Д.

Как я могу сделать массив указателей на них?

Я попробовал следующее, но они не работают ( предупреждение: инициализация из несовместимого типа указателя ):

int *shapes[]=  {&shape1,&shape2};

int *shapes[]=  {shape1,shape2};

int **shapes[]= {&shape1,shape2};

Любая помощь?

Ответы [ 3 ]

5 голосов
/ 28 апреля 2009

Полагаю, я только что подтвердил правильность написанного. Следующие работы, как и ожидалось:

#include <stdio.h>

int main(int argc, char **argv) {

int shape1[5][3] =  {1,0,0,
                 1,0,0,
                 1,0,0,
                 1,0,0,
                 1,0,0};

int shape2[5][3] =  {0,0,0,
                 0,0,0,
                 0,1,1,
                 1,1,0,
                 0,1,0};

typedef int (*shapes_p)[3];
shapes_p shapes[2] = { shape1, shape2 };

shapes[0][1][0] = 5;
shapes[1][1][0] = 5;

printf("shape1[1][0] == %d\n", shape1[1][0]);
printf("shape2[1][0] == %d\n", shape2[1][0]);

}

Следует помнить, что тип shape1 и shape2 на самом деле:

int *shape1[5];

В вашей памяти есть 3 смежных массива по 5 дюймов каждый. Но фактическим типом является указатель на массив из 5-ти дюймов. Когда вы пишете:

shape1[1][2] = 1;

вы говорите компилятору проиндексировать второй массив int [5] и затем получить доступ к третьему элементу этого массива. На самом деле компилятор выполняет арифметику указателей на указанный базовый тип, в данном случае int [5]. Вы можете сделать то же самое с помощью следующего кода:

int *p = shapes1[0];
p+7 = 1;  // same as shape1[1][2] = 1;

Так что, если вы хотите, чтобы массив указателей указывал на int * [5], вы должны сделать:

typedef int (*shapes_p)[5];
shapes_p shapes[2];
3 голосов
/ 28 апреля 2009

Прежде всего, первая привязка массива относится к самому внешнему измерению массива, поэтому вам, вероятно, следует объявить shape1 как:

int shape1[5][3] =  {1,0,0,
                     1,0,0,
                     1,0,0,
                     1,0,0,
                     1,0,0};

и аналогично для shape2.

[РЕДАКТИРОВАТЬ: я изменил тип shapes ниже, чтобы соответствовать ответ Роберта Барнса - мы не хотим, чтобы самый внешний индекс был включен в этот тип! ]

Нужное вам немного странное имя:

int (*shapes[])[3] = { shape1, shape2 };

Это позволяет элементу в строке 4, столбце 1 shape2 быть адресованным с помощью

shapes[1][3][0]

Разбивка подвыражений и их типов C:

shapes            // has type "int (*x[2])[3]" (decays to "(**x)[3]")
shapes[1]         // has type "int (*x)[3]"
shapes[1][3]      // has type "int x[3]" (decays to "int *x")
shapes[1][3][0]   // has type "int x"

(Обратите внимание, что в приведенные выше типы была включена фиктивная x, чтобы сделать их более понятными - фактически этот идентификатор не является частью типа.)

Практическое правило для декодирования типов C / C ++ гласит: «начиная с имени переменной, читайте вправо, когда можете, и влево, когда нажимаете закрывающую скобку». Таким образом, расшифрованное имя типа для shapes:

Массив указателей на массив из 3 целых чисел.

В общем, гораздо лучше использовать typedef s для этих сложных типов, как предлагает .

.
3 голосов
/ 28 апреля 2009

Обновлено Исправлен тип. Спасибо j_radom_hacker за то, что обратили на это мое внимание!

[РЕДАКТИРОВАТЬ: На самом деле тип здесь был неправильный - см. Ответ Роберта С. Барнса для правильного использования типа.]

Сначала выясните тип shape1 и shape2:

typedef int (*shape_array_t)[5];

Теперь используйте это:

shape_array_t sat[] = { shape1, shape2 };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...