Подтвердить что ты не робот

Многомерные массивы С++ в куче

Как бы я мог динамически распределять многомерный массив?

4b9b3361

Ответ 1

Если вы уже знаете размер вложенных измерений, вы также можете буквально выделить многомерный массив с помощью 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, может быть передано определенное время выполнения. Поскольку он не является частью оператора типа, это возвращает новые. Это хорошо, если вы знаете количество столбцов, но хотите, например, сохранить число строк. Typedef упрощает чтение кода.

Ответ 2

Смотрите это: Часто задаваемые вопросы по С++ от Marshall Cline

См. "Как назначить многомерные массивы с помощью новых?" и "Но предыдущий код часто задаваемых вопросов - SOOOO, сложный и подверженный ошибкам! Нет ли более простого способа?" разделы.

Ответ 3

Для полноты, вот лучший способ сделать это на С++, когда вы заранее знаете границы массива. Преимущество использования следующего класса заключается в том, что вам не нужно беспокоиться о вызове 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);

edit: и, пока я нахожусь здесь, вот настройка, которую вы можете использовать, если не знать границы массива до времени выполнения:

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);

Ответ 4

Как насчет использования 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;

}

Ответ 5

Здесь реализована реализация; Я объявляю единый непрерывный блок 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;

Ответ 6

std::vector<std::vector<int> > следует упомянуть, поскольку это часто самый простой способ. Однако имейте в виду, что он не прямоугольный. Не каждый std::vector<int> должен иметь одинаковую длину.

Ответ 7

Я удивлен, что никто еще не упомянул boost::multi_array. Мне понадобился 2D-массив в программе только на прошлой неделе, и оказалось, что это намного проще и быстрее кода, чем домашние решения, которые я придумал раньше (все из которых упоминаются в других комментариях).

Ответ 8

Ваш цикл не будет правильно записывать значения указателя в 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;

Ответ 9

В качестве другой альтернативы STLSoft включает fixed_array_2d (а также версии 3D и 4D). По сравнению с предлагаемыми здесь решениями для дома, он имеет аналогичную реализацию, но имеет более полный набор функций (полная поддержка итераторов и т.д.). По сравнению с boost:: multi_array он легче и проще на несовместимых компиляторах С++, но (намеренно) не хватает некоторых функций multi_array.

Ответ 10

Вы можете индексировать один размер как 2, 3 или N мерный, если вы просто пробегаете нужное количество элементов. Например, если у меня есть 10 строк и 10 столбцов, я знаю, что если я на третьей строке, мне придется пройти по крайней мере 30 элементов, чтобы добраться до него.

Как-то я предпочитаю эту нотацию для простых 2D-массивов, так как мне не нужно беспокоиться о вложенных уровнях указателей. Недостатком является обозначение индекса messier. Вот пример с 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';
}

Ответ 11

Мой вопрос здесь охватывает почти ту же тему довольно хорошо благодаря некоторым превосходным ответам. Однако он не охватывает N-мерные массивы, которые я также не видел в ответах здесь, но это было бы полезно.

Ответ 12

Это воспроизведение сообщения в другом потоке. Он делает именно то, что вы хотите, без необходимости знать размеры массива заблаговременно и без использования boost или STL.

Вот процедура, которая выделяет трехмерный массив измерения N1 x N2 x N3 в смежном пространстве памяти, позволяя вам синтаксис a [i] [j] [k] для доступа оператора. Массив является динамическим, но непрерывным, поэтому он представляет собой огромный плюс над вектором < > approach и циклами новых вызовов [].

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 }}
}