




Вот реализация, которую я получил; Я объявляю один непрерывный блок int вместо создания новых блоков внутри цикла for, поэтому я не вызываю сбои страниц повсюду. Спасибо eJames за указание на то, почему изначально этот код был взломан.
int width = 10, height = 10, totalSize = width*height;
int **myArray = new int*[width];
int *data = new int[totalSize];
for ( int i = 0; i < height; ++i )
{
myArray[i] = data + (i*width);
}
// do some things here
delete[] data;
delete[] myArray;
Этот код не будет работать, как показано. В частности, записи в myArray [i] в вашем цикле будут повсюду. Смотрите мой измененный цикл здесь: stackoverflow.com/questions/340943/…
Если вы уже знаете размер вложенных измерений, вы также можете буквально выделить многомерный массив, используя new:
typedef int dimensions[3][4];
dimensions * dim = new dimensions[10];
dim[/* from 0 to 9 */][/* from 0 to 2 */][/* from 0 to 3 */] = 42;
delete [] dim;
вместо 10 может быть передано значение, определенное во время выполнения. Это разрешено, поскольку оно не является частью возвращаемого оператора типа new. Это удобно, если вы знаете количество столбцов, но хотите, например, сохранить переменную количества строк. Typedef упрощает чтение кода.
это неприятный ответ: stackoverflow.com/questions/198051/…, но, надеюсь, он отвечает на ваши опасения :)
Хорошенькая, литб. Я понятия не имел, что вы можете это сделать.
Ваш цикл не будет правильно записывать значения указателя в myArray. Вместо этого я бы предложил следующее:
int width = 10;
int height = 10;
int ** myArray = new int*[width];
int * data = new int[width*height];
int * index = data;
for (int i = 0; i < width; i++)
{
myArray[i] = index;
index += height;
}
// ...
delete[] data;
delete[] myArray;Ты прав; У меня это работало, и я реорганизовал его, не проверяя, работает ли оно. Может, стоит перестать ломать сборку ...
Посмотри это: C++ FAQ от Маршалла Клайна
См. «Как разместить многомерные массивы с помощью new?» и "Но код из предыдущего FAQ ТАКОЕ сложен и подвержен ошибкам! Нет ли более простого способа?" разделы.
Я давно не думал о C++ FAQ. Наряду с книгой Строструпа, это было одно из моих любимых чтений по программированию.
FAQ [16.16] не кажется правильным. Он выделяет память для строк с помощью new []. Затем устанавливает каждый указатель в NULL и перераспределяет его. Он никогда не освобождает память, для которой установлено значение NULL, что приводит к утечке этой памяти. Пожалуйста, проверьте.
Следует упомянуть std::vector<std::vector<int> >, часто это самый простой способ. Однако имейте в виду, что он не прямоугольный. Не все std::vector<int> должны иметь одинаковую длину.
Для одномерного массива это проще, но два измерения усложняют ситуацию. Вы должны явно инициализировать каждый элемент желаемым размером.
Верно, но это не сложно: std :: vector <std :: vector <int>> myarray (height, std :: vector <int> (width)); создает прямоугольник, полный нулей, индексированный [строка] [столбец]. Строки в памяти непрерывны, столбцы - нет.
@MarkRansom, на самом деле, для меня это преимущество этого метода. boost::multi_array - отличный контейнер, когда длины размеров согласованы, в то время как vector<vector<...>> - это способ пойти для динамических массивов некостентной длины ... который, по общему признанию, почти никогда не нужен ... но когда это так, это путь идти!
Для полноты, вот лучший способ сделать это на C++, когда вы заранее знаете границы массива. Преимущество использования следующего класса заключается в том, что вам не нужно беспокоиться о вызове delete [] для ваших данных. Это означает, что этот класс будет безопасным для исключений, как и все другие замечательные вещи о RAII.
template<typename T, int width, int height>
class MultiArray
{
private:
typedef T cols[height];
cols * data;
public:
T& operator() (int x, int y) { return data[x][y]; }
MultiArray() { data = new cols[width]; }
~MultiArray() { delete [] data; }
};Использование:
MultiArray<int, 10, 10> myArray;
myArray(2, 3) = 4;
cout << myArray(2, 3);редактировать: и, пока я на нем, вот настройка, которую вы можете использовать, если вы не знаете границы массива до времени выполнения:
template<typename T>
class Array2D
{
private:
const int width;
T * data;
public:
T& operator() (int x, int y) { return data[y*width + x]; }
Array2D(const int w, const int h) : width(w) { data = new T[w*h]; }
~Array2D() { delete [] data; }
};Использование:
Array2D myArray(10, 10);
myArray(3, 4) = 42;
cout << myArray(3, 4);Вы можете проиндексировать одномерное как 2-, 3- или N-мерное, если вы просто разместите нужное количество элементов. Например, если у меня есть 10 строк и 10 столбцов, я знаю, что если я нахожусь в строке 3, мне придется пройти не менее 30 элементов, чтобы добраться до нее.
Почему-то я предпочитаю эту нотацию для простых 2D-массивов, поскольку мне не нужно беспокоиться о вложенных уровнях указателей. Обратной стороной является более беспорядочная нотация индекса. Вот пример с 2D-массивом с n строками и m столбцами:
int *matrix = new int[n*m];
//set element (3,7) to 10
matrix[3*m+7] = 10;
//print the matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << matrix[i*m+j] << ' ';
}
cout << '\n';
}
Я удивлен, что еще никто не упомянул boost::multi_array. На прошлой неделе мне понадобился 2D-массив в программе, и я обнаружил, что его намного проще и быстрее кодировать, чем самодельные решения, которые я придумал раньше (все из которых упоминаются в других комментариях) .
Как насчет использования Boost.Multiarray? Я считаю, что это хорошо отвечает вашим потребностям! http://www.boost.org/doc/libs/1_37_0/libs/multi_array/doc/user.html#sec_introduction
Вот выдержка со страницы документации:
#include < boost/multi_array.hpp >
#include < cassert >
int main ()
{
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array< double, 3 > array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
В качестве другой альтернативы STLSoft включает в себя класс fixed_array_2d (а также версии 3D и 4D). По сравнению с приведенными здесь домашними решениями, он имеет аналогичную реализацию, но более полный набор функций (полная поддержка итераторов и т. д.). По сравнению с boost :: multi_array, он легче и проще для не совсем совместимых компиляторов C++, но (намеренно) лишен некоторых функций multi_array.
Это воспроизведение сообщения в другой ветке. Он делает именно то, что вы хотите, без необходимости заранее знать размеры массива и без использования ускорения или STL.
Это процедура, которая выделяет трехмерный массив размерности N1 x N2 x N3 в непрерывном пространстве памяти, позволяя вам использовать синтаксис a [i] [j] [k] для доступа оператора. Массив является динамическим, но непрерывным, так что это огромный плюс по сравнению с подходом vector <> и циклами вызовов new [].
template <class T> T ***Create3D(int N1, int N2, int N3)
{
T *** array = new T ** [N1];
array[0] = new T * [N1*N2];
array[0][0] = new T [N1*N2*N3];
int i,j,k;
for( i = 0; i < N1; i++) {
if (i < N1 -1 ) {
array[0][(i+1)*N2] = &(array[0][0][(i+1)*N3*N2]);
array[i+1] = &(array[0][(i+1)*N2]);
}
for( j = 0; j < N2; j++) {
if (j > 0) array[i][j] = array[i][j-1] + N3;
}
}
cout << endl;
return array;
};
template <class T> void Delete3D(T ***array) {
delete[] array[0][0];
delete[] array[0];
delete[] array;
};
И позже в вашей рутине реализации ...
int *** array3d;
int N1=4, N2=3, N3=2;
int elementNumber = 0;
array3d = Create3D<int>(N1,N2,N3);
//equivalently, a 'flat' array could be obtained with
//int * array = array3d[0][0];
cout << "{" << endl;
for (i=0; i<N1; i++) {
cout << "{";
for (j=0; j<N2; j++) {
cout << "{";
for (k=0; k<N3; k++) {
array3d[i][j][k] = elementNumber++;
cout << setw(4) << array3d[i][j][k] << " ";
//or if you're using the flat array:
//array[i*N2*N3 + j*N3 + k] = elementNumber++;
}
cout << "}";
}
cout << "}";
cout << endl ;
}
cout << "}" << endl;
Delete3D(array3d);
Дает результат:
{
{{ 0 1 }{ 2 3 }{ 4 5 }}
{{ 6 7 }{ 8 9 }{ 10 11 }}
{{ 12 13 }{ 14 15 }{ 16 17 }}
{{ 18 19 }{ 20 21 }{ 22 23 }}
}
Ааа, это хороший вопрос.