тип переменного размера, объявленный вне какой-либо функции

StackOverflow https://stackoverflow.com/questions/1435004

Вопрос

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

int random[height][width];

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

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

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

Это было полезно?

Решение

Я собираюсь подойти прямо сейчас и сказать вам, что многомерные массивы не стоят мозговых усилий в 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 для размещения данных или использовать тип контейнера.

Другие советы

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

Когда массив передается в качестве параметра функции (передача по значению), он превращается в указатель на первый элемент массива. Даже если вы можете четко прочитать в сигнатуре размеры массива, эти измерения игнорируются компилятором. Такое поведение совместимо с 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 о перегрузке операторов, обеспечивающей реализацию 2D-матрицы. Как только вы это реализовали, вы можете просто использовать это как параметр для функций / методов.

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

Я проиллюстрирую это примером:

//глобальные

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 определяется во время компиляции, и компилятор может знать размер массива во время компиляции.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top