тип переменной размера, объявленный вне любой функции - PullRequest
1 голос
/ 16 сентября 2009

при объявлении двумерного массива

int random[height][width];

, а затем использовать его в функции

void populate(int random[height][width], int x, int y)

выдает тип переменной размера ошибки, объявленный вне какой-либо функции. Я знаю, что делаю что-то не так, и это что-то маленькое. У меня просто плохая память ...

Ответы [ 5 ]

4 голосов
/ 16 сентября 2009

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

inline int index (int x, int y)
{
  return x + y * width;
}

Теперь для вашей проблемы. C ++ не поддерживает массивы переменной длины C99. Компилятор должен знать, во время компиляции, размер массива. Например, следующее не будет работать.

int dim = 4;
int ar[dim];

Если бы dim было const, это сработало бы, потому что компилятор мог бы точно сказать, насколько широким должен быть ar (поскольку значение dim не изменится). Вероятно, это проблема, с которой вы столкнулись.

Если вы хотите изменить размер во время компиляции, вам нужно сделать что-то более сложное, например написать шаблонную ссылку. Вы не можете использовать указатель для многомерных массивов из-за способа их размещения в C / C ++. Шаблонный пример может выглядеть следующим образом:

template <int Width, int Height>
void populate(int (&(&random)[Width])[Height], int x, int y);

Это безобразно.

Для выполнения вам потребуется использовать new для выделения данных или использовать тип контейнера.

1 голос
/ 24 ноября 2011

Я проиллюстрирую, например:

// Глобал

const int ARRAY_SIZE = 16 struct ArrayType_t arrayType[ARRAY_SIZE];

Хотя ARRAY_SIZE объявлен как константа int, его значение не инициализируется во время компиляции, и, следовательно, компилятор не знает размер массива и выдает такую ​​ошибку. Однако, если вы сделаете это как хеш #define ARRAY_SIZE 16 struct ArrayType_t arrayType[ARRAY_SIZE] ===> это работает, потому что ARRAY_SIZE определен в время компиляции, и компилятор может знать размер массива во время компиляции.

1 голос
/ 17 сентября 2009

Когда массив передается в качестве параметра функции (передача по значению), он превращается в указатель на первый элемент массива. Даже если вы можете четко прочитать в сигнатуре размеры массива, эти измерения игнорируются компилятором. Такое поведение совместимо с C.

Используя C ++, вы можете передавать массив по ссылке, и это больше не будет проблемой.

int extract_value( int (&a)[10][10], int row, int col ) {
   return a[row][col];
}
int main() {
   int a[10][10] = {};
   a[5][5] = 1;
   std::cout << extract_value( a, 5, 5 ) << std::endl;
   int b[5][5];
//   extract_value( b, 2, 2 ); // error: the function takes an array of 10x10
}

Параметр функции должен точно соответствовать, то есть он принимает только массив 10х10 элементов. Вы можете избавиться от этого ограничения, шаблонизируя функцию по размерам массива. После того, как вы на это, также введите:

template <typename T, int Rows, int Cols>
T extract_value( T (&a)[Rows][Cols], int row, int col ) {
   return a[row][col];
}
int main() {
   int a[5][7] = {};
   extract_value( a, 3, 4 );
   int b[8][2] = {};
   extract_value( b, 7, 1 ); // correct, the compiler matches sizes
   double c[4][4] = {};
   extract_value( c, 2, 2 ); // different types are allowed
}

Это решение все еще громоздко в том смысле, что размеры должны быть постоянными времени компиляции, а массив должен быть выделен в стеке. Решением этой проблемы является определение некоторого класса, который занимает динамическую память в буфере (линейном) и имеет преобразование из N-координатной системы в одномерный массив для получения значений, как это было предложено ранее. Вы можете получить некоторые подсказки о том, как это сделать, в этом FAQ о перегрузке операторов, которая обеспечивает реализацию двумерной матрицы. Как только вы это реализовали, вы можете просто использовать это как параметр для функций / методов.

Я бы порекомендовал следовать этому последнему пути: инкапсулировать N-мерный массив в класс, который обеспечивает преобразования в одномерный вектор (в C ++ FAQ Lite используется необработанный указатель, я предпочитаю контейнеры STL).

1 голос
/ 16 сентября 2009

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

0 голосов
/ 17 сентября 2009

Вы можете использовать что-то вроде этого:

void populate(int height, int width, int **random)
{
    //here you can work from random[0][0] to random[height][width]
}

тогда вы можете использовать его так:

int main()
{
    int height=10;
    int width=20;
    int **myarray = new int*[height];
    for( int i=0; i< height; i++ ) myarray[i] = new int[width];
    populate( height, width, myarray);
}

но, конечно, вам придется остерегаться переполнения буфера

...