Непрерывные, динамические, многомерные массивы в C++
Когда вы динамически создаете одномерный массив с помощью new
, вы получаете непрерывный блок памяти.
cout << "Ints have size " << sizeof(int) << endl;
int c= 10;
int *i= new int[c];
for(int j= 0; j < c; j++)
{
cout << j << " " << &i[j] << endl;
}
На моей машине вывод выглядит следующим образом:
Ints have size 4
0 0x8107008
1 0x810700c
2 0x8107010
3 0x8107014
4 0x8107018
5 0x810701c
6 0x8107020
7 0x8107024
8 0x8107028
9 0x810702c
Обратите внимание, что каждый элемент массива идет в памяти через 4 байта после предыдущего элемента (это шестнадцатеричные адреса, поэтому мы считаем 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, …).
Теперь, предположим, мы хотим создать простой двумерный массив. Например, 2x2.
cout << "Ints have size " << sizeof(int) << endl;
int n= 2;
int m= 2;
int **i= new int*[n];
for(int j= 0; j < m; j++)
{
i[j]= new int[m];
}
for(int j= 0; j < n; j++)
{
for(int k= 0; k < m; k++)
{
cout << j << " " << k << " " << &i[j][k] << endl;
}
}
Массив теперь не непрерывен.
Ints have size 4
0 0 0x851a018
0 1 0x851a01c
1 0 0x851a028
1 1 0x851a02c
Чтобы сделать 2D массив непрерывным, мы должны вручную посчитать указатели, что обычно делает за нас компилятор.
cout << "Ints have size " << sizeof(int) << endl;
int rows= 2;
int cols= 3;
int **i= new int*[rows];
int size= rows*cols;
i[0]= new int[size];
for(int j= 1; j < rows; j++)
{
i[j]= &i[0][j*cols];
}
for(int j= 0; j < rows; j++)
{
for(int k= 0; k < cols; k++)
{
cout << j << " " << k << " " << &i[j][k] << endl;
}
}
delete[] i;
И что на выходе?
Ints have size 4
0 0 0x9275018
0 1 0x927501c
0 2 0x9275020
1 0 0x9275024
1 1 0x9275028
1 2 0x927502c
То, что нужно!
Создание такого двумерного массива можно вывести в отдельную функцию. Она создает пул памяти и массив указателей, каждый из которых указывает на позицию в пуле памяти. Ниже приведен код на базе шаблона.
template <typename T>
T** create2DArray(unsigned nrows, unsigned ncols, const T& val = T())
{
T** ptr = new T*[nrows]; // разместить указатели
T* pool = new T[nrows*ncols]{val}; // разместить пул
for (unsigned i = 0; i < nrows; ++i, pool += ncols )
ptr[i] = pool;
return ptr;
}
template <typename T>
void delete2DArray(T** arr)
{
delete [] arr[0]; // удалить пул
delete [] arr; // удалить указатели
}
int main()
{
double **dPtr = create2DArray<double>(10,10);
dPtr[0][0] = 10; // для примера
delete2DArray(dPtr); // высвободить память
}