#c #multidimensional-array #dynamic-arrays
#c #многомерный массив #динамические массивы
Вопрос:
Я разрабатываю 2d-платформер. Все было хорошо, пока у меня не возникла трудноразрешимая проблема. Карта уровней хранится в динамическом многомерном массиве (char **map). Это работает нормально, пока я не захочу переопределить это
Вот часть кода:
Mapamp; Map::operator=(const Mapamp; rhs)
{
if(width!=0||height!=0)
{
for(int i=0;i<width;i )
delete[] map[i];
delete[] map;
} //deleting previously created array
height=rhs.height;
width=rhs.width; //receiving other map's size
map=new char* [width];
walkmap=new unsigned char* [width];
objmap=new char* [width];
for(int i=0;i<width;i )
{
*(map i)=new char[height];
} //creating new array
for(int h=0;h<height;h )
for(int w=0;w<width;w )
{
map[w][h]=rhs.map[w][h];
} //receiving new values
//...
}
В первый раз все работает нормально, но когда мне нужно переопределить массив во второй раз, моя программа вылетает в той части, когда массив получает новые значения от другого. Может быть, я что-то пропустил, но я не могу это найти! Я искал эту проблему, но не нашел, что я делаю неправильно. Помогите мне, пожалуйста.
Комментарии:
1. Вы пропустили объявление типа (def?)
Map
, что довольно важно для вопроса.2. Также я бы изменил
*(map i)
наmap[i]
только потому, что это гораздо более описывает то, чего вы пытаетесь достичь с помощью этой строки, ИМХО.
Ответ №1:
Как всегда, Boost имеет элегантный класс многомерных массивов, экономящий память:
http://www.boost.org/doc/libs/1_39_0/libs/multi_array/doc/user.html
Например, для настройки массива значений bool размером 10 x 20:
boost::multi_array mtaFlagMatrix(boost::extents[10][20]);
Затем для доступа к его элементам:
mtaFlagMatrix[2][6] = false; // indexes are zero-based - just like normal C arrays
...
if ( mtaFlagMatrix[2][6] )
{
...
}
Затем вы можете изменить размер массива таким образом (существующие значения сохраняются):
typedef boost::multi_array array_type;
array_type::extent_gen extents;
array_type A(extents[3][3][3]);
A[0][0][0] = 4;
A[2][2][2] = 5;
A.resize(extents[2][3][4]);
assert(A[0][0][0] == 4);
// A[2][2][2] is no longer valid.
Это сэкономило мне много времени на тестирование для крайних случаев.
Комментарии:
1. О, я не хочу использовать дополнительные компоненты, потому что мой код будет трудно понять. Мне не нужно менять размер очень часто. Всего 2 или 3 раза! И использование библиотек не поможет мне понять, когда я был неправ, D:
Ответ №2:
Ваш 2d-массив не освобожден должным образом. Я советую вам использовать способ Iliffe для выделения 2d-массивов, который быстрее и безопаснее в использовании:
char** alloc_array( int h, int w )
{
typedef char* cptr;
int i;
char** m = new cptr[h];
m[0] = new char[h*w];
for(i=1;i<h;i ) m[i] = m[i-1] w;
return m;
}
void release_array(char** m)
{
delete[] m[0];
delete[] m;
}
int main()
{
int r,c;
char** tab;
int width = 5;
int height = 3;
tab = alloc_array(height, width); /* column first */
for(r = 0;r<height; r)
for(c = 0;c<width; c)
tab[r][c] = (1 r c);
for(r = 0;r<height; r)
{
for(c = 0;c<width; c)
{
printf("%dt",tab[r][c]);
}
puts("");
}
release_array(tab);
}
Это можно легко инкапсулировать в аккуратный класс 2d-массива или заставить использовать std::vector вместо необработанного выделения. Предпочитаю этот способ создания 2d-массива, поскольку он удобен для кэширования, обеспечивает доступ к [][] и работает не медленнее, а иногда и быстрее, чем полиномиальный одномерный доступ.
Комментарии:
1. Спасибо, я попробую использовать этот метод
2. Ого, та же проблема. В первый раз все работает нормально, затем я удаляю ранее созданный массив, создаю новый массив (теперь все в порядке), но когда я начинаю присваивать некоторые новые значения новому массиву, программа снова вылетает, то же самое происходит в моем коде.
3. вы делаете что-то неправильно в другом месте. можете ли вы показать мне свой обновленный код для обозначения этих функций
4. pastebin.com/Gtvnf2wA Вот она. (В первый раз rhs.tileset!=0, но во второй раз это 0
5. О, и другие массивы используют тот же метод (но это не показано в коде)