C ++ 2D Dynamic Array - PullRequest
       23

C ++ 2D Dynamic Array

3 голосов
/ 19 февраля 2010

Я пытаюсь динамически назначить 2d массив указателю в инициализаторе конструктора.

FooBar::FooBar()
    : _array( new int[10][10] )
{ }
int **_array;

Однако это не работает. Я понимаю, что многомерные массивы расположены немного по-другому. Кто-нибудь может уточнить это с объяснением?

Заранее спасибо.

Ответы [ 5 ]

7 голосов
/ 19 февраля 2010

Некоторые ответы здесь говорят, что двумерный массив - это массив указателей на другие массивы. Это не так (где хранить указатели, если все, что вы выделяете - это данные массива !?). Вместо этого двумерный массив - это массив других массивов. Таким образом, вам придется изменить тип вашего члена:

FooBar::FooBar()
    : _array( new int[10][10] )
{ }
int (*_array)[10];

Это потому, что new[] возвращает указатель на первый элемент созданного массива. Этот элемент представляет собой массив из 10 целых чисел, и, следовательно, тип элемента изменяется. Если синтаксис вас пугает, упростите его с помощью шаблона (этот шаблон эквивалентен boost::identity).

template<typename T> struct identity { typedef T type; };

FooBar::FooBar()
    : _array( new int[10][10] )
{ }
identity<int[10]>::type *_array;

Это эффективно работает как typedef на месте. Конечно, как и при любом использовании new[], для него необходим правильный delete[], помещенный в деструктор и вызываемый при разрушении вашего объекта.

Поскольку new[] выделяет массив элементов, типы которых известны во время компиляции, вы можете установить только первое (самое внешнее) измерение в значение времени выполнения - все остальные должны иметь значения, известные во время компиляции. Если это не то, что вы хотите, вам придется выделить массив указателей, как говорят некоторые другие ответы.

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

4 голосов
/ 19 февраля 2010

Двумерный массив в C - это массив указателей на другие массивы.

Предполагая, что у нас есть массив 3x3 a (напечатано int**):

a[0] (a[0] is of type int*) = [0][1][2]
a[1] (a[1] is of type int*) = [0][1][2]
a[2] (a[2] is of type int*) = [0][1][2]

Это означает, что необходимы два прохода выделения, один для массива указателей (int **), а остальные для каждого элементов этого массива.

Первый проход, выделение массива указателей:

int** a = new int*[10];

Второй проход, для каждого из элементов a, выделяется новый массив:

for(int i=0; i<10; ++i)
    a[i] = new int[10];

Это даст вам «двумерный» массив в C ++.

Как видите, это может быть довольно громоздким в более высоких измерениях, поэтому другой трюк состоит в том, чтобы выделить 10 * 10 элементов и использовать массив как 2D (он же "проекция"):

const int ARRAY_WIDTH = 10;
const int ARRAY_HEIGHT = 10;
int* a = new int[ARRAY_WIDTH * ARRAY_HEIGHT];

    // To access a[5][2] you would use: 
a[5 + (2 * ARRAY_WIDTH)] = 0;
3 голосов
/ 19 февраля 2010
int **array  = new int *[10];

for(int i= 0; i< 10;i++)
{
    array[i] = new int[10];
}
0 голосов
/ 17 февраля 2011

Если вам не важна производительность, вы можете использовать следующее:

//vec2d.h
#include<vector>

template<class T>
void init2DVect(std::vector< std::vector<T> >& _T, size_t sx, size_t sy)
{
  _T.resize( sx );
  for(size_t i =0; i < sx; ++i)
  {
    std::vector<T> ins_v(sy);
    _T[i] = ins_v;
  }
}

Пример использования:

//file: vec2d_test.cpp
#include "vec2D.h"

#include<cassert>

int main()
{
  std::vector< std::vector<int> > vi;
  size_t sx = 5;
  size_t sy = 7;
  init2DVect(vi, sx, sy);

  for(size_t i = 0; i < sx; ++i)
  {
    for(size_t j = 0; j < sy; ++j)
    {
      vi.at(i).at(j) = i*j;
    }
  }

  for(size_t i = 0; i < sx; ++i)
  {
    for(size_t j = 0; j < sy; ++j)
    {
      assert( vi.at(i).at(j) == i*j );
      assert( vi[i][j] == i*j );
    }
  }   

  return 0;
}

Это имеет то преимущество, что вам не нужно беспокоиться о памяти, и вы можете использовать функцию vector :: at (), чтобы выдать исключение, если вы выходите за пределы ... хорошо для домашней работы C ++, но вектор из std :: vector обязан быть не самым быстрым способом сделать это.

В противном случае библиотека TNT добивается цели.

0 голосов
/ 19 февраля 2010

Если вы используете новый, вам нужно выделить каждую часть второго измерения по отдельности.

int **Array;
Array = new int*[10];
for (int i = 0; i < 10; i++) {
    Array[i] = new int[10];
}
...