Относительно двумерного массива - PullRequest
1 голос
/ 19 апреля 2010

У меня проблемы с использованием двухмерного массива.

static const int PATTERNS[20][4];

static void init_PATTERN()
{
   // problem #1
   int (&patterns)[20][4] = const_cast<int[20][4]>(PATTERNS);  
   ...
}

extern void UsePattern(int a, const int** patterns, int patterns_size);

// problem #2
UsePattern(10, PATTERNS, sizeof(PATTERNS)/sizeof(PATTERNS[0]));

В первом утверждении мне нужно привести const к двумерному массиву PATTERNS. Причина этого в том, что функция init вызывается только один раз, а в оставшемся коде PATTERNS только для чтения.

Во втором утверждении мне нужно передать массив PATTERNS в аргумент int**. Прямая передача привела к ошибке компиляции.


Я решил проблему, примерно в то же время, когда @Andrey опубликовал ответ. Да int[][] не может быть приведено к int**.

Его можно преобразовать в int* - &(PATTERNS[0][0]), а прототип функции должен быть изменен с размером строки (количество элементов в строке). Массив может быть const_cast с синтаксисом ссылки.

Ответы [ 4 ]

7 голосов
/ 19 апреля 2010

Во-первых, в C ++ нет такого понятия, как приведение к типу массива (или к типу функции). Но это то, что вы пытаетесь сделать. Если вы хотите отбросить константность из чего-либо, вы должны привести либо к указателю, либо к ссылочному типу. В вашем случае у вас есть ссылка на приемном конце приведения, так что сам прицел также должен относиться к типу ссылки

int (&patterns)[20][4] = const_cast<int (&)[20][4]>(PATTERNS); 

Конечно, как уже заметил Билл, отбрасывание константности из постоянного объекта (а затем попытка изменить объект) приводит к неопределенному поведению.

Во-вторых, двумерный массив никуда не может быть передан как указатель int **. Если вы хотите передать ваш PATTERNS куда-нибудь, вы можете передать его как const int (&)[20][4], const int (*)[20][4], const int [][4], const int (*)[4] или что-то подобное, но не как int **. Выполните поиск по SO и / или прочитайте некоторые FAQ в массивах, чтобы понять, почему. Это было объяснено слишком много раз, чтобы повторить это снова.

1 голос
/ 20 апреля 2010

C ++ Массивы сложны. Вы не можете просто бросить их и ожидать, что они будут работать, как на некоторых языках. Единственный способ инициализировать массив из другого массива - это перейти по циклу для и скопировать каждый элемент по отдельности. Это вдвойне подходит для двумерных массивов (то есть вам понадобятся два для циклов).

Кажется, вы пытаетесь сделать это более сложным, чем нужно. Например, если набор значений, которые вы будете назначать для PATTERNS, будет одинаковым при каждом запуске программы, вы можете инициализировать двумерную переменную следующим образом:

static const int foo[2][3] = {{11,12,13},{21,22,23}};

Если набор значений, назначенных для PATTERNS, варьируется от одного исполнения к другому, то вам, вероятно, следует попытаться найти другой способ решения проблемы. Я бы, вероятно, обернул данные в классе, особенно если вы собираетесь использовать двумерные массивы одинакового размера в других местах кода.

1 голос
/ 19 апреля 2010

AndreyT ответ идеально. Я только хотел бы добавить, что я полагаю, что вам лучше использовать класс, который init_PATTERN() работает в конструкторе и переопределяет operator[] для предоставления доступа только для чтения к элементам массива.

Это, конечно, при условии, что вы можете изменить функцию UsePattern, чтобы получить ссылку на такой класс вместо указателя на массив int.

1 голос
/ 19 апреля 2010

Когда вы объявляете PATTERNS как const, компилятор может установить его в постоянной памяти. Вы не можете безопасно выбросить const, если предмет не был первоначально объявлен без const.

Я предполагаю, что ошибка вашего компилятора была cannot convert 'int (*)[4]' to 'int**' for argument '2' to 'void UsePattern(int, int**, int)'?

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