Указатель на динамический массив - PullRequest
0 голосов
/ 07 февраля 2012

Предположим, у меня есть сетка квадрата, определенная так же, как и в классе:

Square (* grid)[];

Это, как ни странно, похоже, прекрасно компилируется. Я думаю, что это будет ошибка, потому что компилятор не знает, насколько большой массив? В любом случае, это означает, что это указатель на массив. Затем для его инициализации я делаю:

grid(new Square[width * height])

Это не принято компилятором, потому что оператор new возвращает указатель на квадраты, а не указатель на массив квадратов. Это имеет смысл, что он делает это. Теперь, есть ли простой способ выполнить то, что я спрашиваю, кроме простого объявления Square ** grid и циклического прохождения по нему и выполнения отдельных выделений для каждого столбца двумерного массива?

Ответы [ 2 ]

3 голосов
/ 07 февраля 2012
Square (* grid)[];

Это, как ни странно, кажется, хорошо компилируется.Я думаю, что это будет ошибка, потому что компилятор не знает, насколько большой массив?

Это объявление указателя на массив, а не массив;Можно объявить указатель на любой неполный тип, включая массив неизвестного размера.Однако это довольно необычная вещь, а не то, что вы хотите для динамического массива.

Теперь, есть ли простой способ выполнить то, что я спрашиваю?

Самый простой динамический массив для использования:

std::vector<Square> grid;

, инициализированный как

grid(width * height)

Если вы действительно хотите управлять памятью самостоятельно, измените указатель на массив науказатель на объект:

Square * grid;

, инициализированный как

grid(new Square[width * height])

Указатель может указывать либо на отдельный объект, либо на начало массива;если он указывает на массив, вы можете использовать [] для него, как для нединамического массива.Убедитесь, что вы освободили его (delete [] grid;), как только закончили с ним.

Если вам нужен 2-мерный массив, часто проще всего использовать 1-мерный массив и обернуть необходимую арифметику вфункция доступа:

Square & get_square(size_t row, size_t col) {
    return grid[row * width + col];
}
0 голосов
/ 07 февраля 2012

Я считаю, что причина Square (* grid)[]; в том, что указатели на неполные типы разрешены, а массив без размера считается неполным типом.

Причина, по которой вы не можете сделать

Square (* grid)[] = new Square[width * height];

даже если кажется, что типы идеально совпадают, это просто еще одно проявление ошибки в дизайне C, когда типы массивов обрабатываются специально. Кажется, что new объект типа Square[] должен возвращать указатель на объект этого типа. Однако вы на самом деле не new используете тип массива, но new[] используете тип элемента Square. Результатом new[] является указатель на тип элемента в соответствии с соглашением C для массивов.

Вы можете использовать приведение, чтобы исправить это, чтобы использовать правильный тип:

// pretend array types behave rationally
Square (* grid)[] = (Square (*)[]) new Square[width * height];
(*grid)[3] = 10;

// the above is equivalent to the following
Square *grid = new Square[width * height];
grid[3] = 10;  

Или вы можете просто сделать это C ++ и использовать std::vector

std::vector<Square> grid(width * height);

Если у вас есть массив фиксированного размера, вы можете использовать std::array

std::array<Square,10> *grid = new std::array<Square,10>;

std::array в значительной степени исправляет все ошибки, допущенные при проектировании типов массивов. Например, std::array не может «забыть» свой размер, функции могут принимать std::array параметров по значению (тогда как с необработанными массивами синтаксис массива просто становится синонимом для указателей), функции могут возвращать std::array, тогда как они необъяснимо запрещены. от возврата массивов (синтаксис будет int foo()[3];), а с std::array нет необходимости в специальном распределителе массива new[], который должен быть сопоставлен с освобождающим массивом delete[] (вместо этого вы можете сказать foo = new std::array<int,3>, а затем 'delete foo;')

...