Непрерывные, динамические, многомерные массивы в C++

Добавлено 19 декабря 2017 в 03:07

Когда вы динамически создаете одномерный массив с помощью 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);  // высвободить память
}

Теги

C++ / CppДинамическое распределение памятиМассивПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.