Распределение 2D матриц по куче в c ++ - PullRequest
4 голосов
/ 07 октября 2011

Я ищу способ размещения 2D (m x n) матрицы в куче, где элементы последовательны в памяти. В настоящее время я знаю два способа сделать это:

Первый подход

int* M = new int[m * n];
  • Pro: размер M может быть определен динамически.
  • Con: индексирование M немного болезненно. (M[i * m + j])

Второй подход

typedef int dim[2];
dim* M = new dim[n];
  • Pro: индексирование M - это именно то, что я хочу.
  • Con: Размер первого измерения (м) не может быть установлен динамически.

Вопрос

Есть ли способ динамического выделения 2D-матрицы в куче, где я могу индексировать элементы с помощью [i][j] и , выделение памяти является последовательным?

Я знаю, что для этого имеет смысл использовать класс, но я специально ищу способ, описанный выше.

Ответы [ 7 ]

3 голосов
/ 07 октября 2011

Вот минимальная версия класса IntArray2D, который я упомянул в своем комментарии:

class IntArray2D
{
    std::vector<int> data_;
    int height_;
    int width_;

public:

    IntArray2D(int height, int width)
    : data_(height * width), height_(height), width_(width) 
    {
    }

    int* operator[](int index)
    {
        return &data_[index * width_];
    }

    const int* operator[](int index) const
    {
        return &data_[index * width_];
    }
};

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

IntArray2D test(100, 10);
test[99][9] = 42;
int i = test[0][0];

Возможно, вы захотите добавить проверку границ, и для этого в обоих измерениях вам нужно вернуть соответствующий прокси-объект вместо указателя. Упражнение оставлено читателю; -)

3 голосов
/ 07 октября 2011

Вы можете попробовать это

int** M = new int*[m];
int *M_data = new int[m*n];

for(int i=0; i< m; ++i) 
{
    M[i] = M_data + i * n;
}
2 голосов
/ 07 октября 2011

ПРИМЕЧАНИЕ: см. Редактирование ниже для способов сделать это.Я сохраню исходное сообщение как есть.

Исходное сообщение

Чтобы оба размера были динамическими, а элементы были последовательными, у вас нет другого пути, чем ваш первый метод .( note : см. Редактирование, есть способы сделать это, но с g ++)

Подумайте об этом так: когда вы говорите компилятору вычислить массив [i] [j], он автоматически переведет его на:

*(array+i*m+j)

, если массив статичен и m (количество столбцов) известно.Или, если массив 2D (типа type **):

*(*(array+i)+j)

Второй случай - это то, как вы обычно делаете это с двумерными массивами, но данные НЕ являются последовательными.Это оставляет вас с первым вариантом.Теперь в первом варианте во время компиляции компилятор должен знать m.Если вы хотите, чтобы m был установлен во время выполнения, компилятор просто не сможет вычислить i*m+j.

Теперь есть способы обойти это.Одним из них является использование классов, как вы упомянули, которые обертывают array = new type[n*m]; и корректно перегружают оператор [].Другой способ сделать это, который потребовал бы больше памяти (и поэтому я лично не рекомендую), это взять второй массив типа type **, и вместо того, чтобы устанавливать для каждого элемента значение new type[m], вы устанавливаете его в началострок в одномерном массиве.

Тем не менее, суть в том, что где-то вам нужно иметь new type[n*m]

Edit: методы для этого, используя g ++

Это появилось из комментариев ниже:

type *array_helper = new type[n*m];
type (*array)[m] = (type (*)[m])array_helper;

Тогда вы можете использовать массив и элементы будут последовательными.

Я тоже попробовал, и это сработало

type array[n][m];

и я распечатал адреса, специально проверил array[i][m-1] и array[i+1][0] и адреса последовательные.

1 голос
/ 08 октября 2011

Выстраивая ответ crazyjul, вы можете сделать это только с одним выделением памяти.

int **arr = new int*[col*(row+1)];
for(int a=0; c<col; ++a){
    arr[a] = (int*)&arr[(a+1)*row];
}
1 голос
/ 07 октября 2011

Вы хотите указатель на (int-массив):

 cin >> w >> h;
 int (*data)[w] = (int (*)[w])new int[w*h];
 for(int y=0;y<h;y++)
 for(int x=0;x<w;x++)
     data[y][x] = (w*y)+x;
0 голосов
/ 07 октября 2011

Используйте повышение array, matrix или STL vector?

Еще одна вещь для вашей матрицы: Почему интерфейс моего класса Matrix не должен выглядеть как массив-массив?

0 голосов
/ 07 октября 2011

C-подобный псевдокод:

int** M = new int*[m];
for(int i in 0..m-1) {
    M[i] = new int[n];
}
...