Вопрос

Как динамически выделить 2D-матрицу в C++?Я попробовал, основываясь на том, что я уже знаю:

#include <iostream>

int main(){
    int rows;
    int cols;
    int * arr;
    arr = new int[rows][cols];
 }

Это работает для одного параметра, но теперь для двух.Что я должен делать?

Это было полезно?

Решение

Матрица на самом деле является массивом массивов.

int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
    matrix[i] = new int[cols];

Конечно, чтобы удалить матрицу, вы должны сделать следующее:

for (int i = 0; i < rows; ++i)
    delete [] matrix[i];
delete [] matrix;
<Ч>

Я только что выяснил другую возможность:

int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
    matrix[0] = new int[rows * cols];
    for (int i = 1; i < rows; ++i)
        matrix[i] = matrix[0] + i * cols;
}

Освободить этот массив проще:

if (rows) delete [] matrix[0];
delete [] matrix;

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

Другие советы

Вы также можете использовать std::vectors для достижения этого:

с использованием std::vector< std::vector<int> >

Пример:

std::vector< std::vector<int> > a;

  //m * n is the size of the matrix

    int m = 2, n = 4;
    //Grow rows by m
    a.resize(m);
    for(int i = 0 ; i < m ; ++i)
    {
        //Grow Columns by n
        a[i].resize(n);
    }
    //Now you have matrix m*n with default values

    //you can use the Matrix, now
    a[1][0]=1;
    a[1][1]=2;
    a[1][2]=3;
    a[1][3]=4;

//OR
for(i = 0 ; i < m ; ++i)
{
    for(int j = 0 ; j < n ; ++j)
    {      //modify matrix
        int x = a[i][j];
    }

}

Попробуйте boost :: multi_array

#include <boost/multi_array.hpp>

int main(){
    int rows;
    int cols;
    boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
 #include <iostream>

    int main(){
        int rows=4;
        int cols=4;
        int **arr;

        arr = new int*[rows];
        for(int i=0;i<rows;i++){
           arr[i]=new int[cols];
        }
        // statements

        for(int i=0;i<rows;i++){
           delete []arr[i];
        }
        delete []arr;
        return 0;
     }
arr = new int[cols*rows];

Если вы не возражаете против синтаксиса

arr[row * cols + col] = Aij;

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

for(int i=0;i < rows*cols;++i)
   matrix[i]=someOtherMatrix[i];

на одну строку короче

for(int r=0;i < rows;++r)
  for(int c=0;i < cols;++s)
     matrix[r][c]=someOtherMatrix[r][c];

хотя добавление строк в такую ​​матрицу более болезненно

или вы можете просто выделить одномерный массив, но ссылочные элементы в двухмерном виде:

для адресации строки 2, столбца 3 (верхний левый угол - строка 0, столбец 0):

arr [2 * MATRIX_WIDTH + 3]

где MATRIX_WIDTH - количество элементов в строке.

Другой ответ, описывающий массивы массивов, правильный.
НО, если вы планируете делать что-нибудь математическое с массивами - или вам нужно что-то особенное, например, разреженные матрицы, вы должны взглянуть на одну из многих математических библиотек, таких как TNT , прежде чем изобретать слишком много колес

У меня есть этот класс сетки, который можно использовать в качестве простой матрицы, если вам не нужны математические операторы.

/**
 * Represents a grid of values.
 * Indices are zero-based.
 */
template<class T>
class GenericGrid
{
    public:
        GenericGrid(size_t numRows, size_t numColumns);

        GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);

        const T & get(size_t row, size_t col) const;

        T & get(size_t row, size_t col);

        void set(size_t row, size_t col, const T & inT);

        size_t numRows() const;

        size_t numColumns() const;

    private:
        size_t mNumRows;
        size_t mNumColumns;
        std::vector<T> mData;
};


template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
    mNumRows(numRows),
    mNumColumns(numColumns)
{
    mData.resize(numRows*numColumns);
}


template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
    mNumRows(numRows),
    mNumColumns(numColumns)
{
    mData.resize(numRows*numColumns, inInitialValue);
}


template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
    return mData[rowIdx*mNumColumns + colIdx];
}


template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
    return mData[rowIdx*mNumColumns + colIdx];
}


template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
    mData[rowIdx*mNumColumns + colIdx] = inT;
}


template<class T>
size_t GenericGrid<T>::numRows() const
{
    return mNumRows;
}


template<class T>
size_t GenericGrid<T>::numColumns() const
{
    return mNumColumns;
}

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

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

///
/// Matrix Allocator Utility
/// @param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// @param iRows Number of rows.
/// @param iColumns Number of columns.
/// @return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray, 
               size_t iRows, 
               size_t iColumns)
{
   bool l_bResult = false;
   if (pppArray != 0) // Test if pointer holds a valid address.
   {                  // I prefer using the shorter 0 in stead of NULL.
      if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
      {                        // The "double-not" evaluates a little quicker in general.
         // Allocate and assign pointer array.
         (*pppArray) = new T* [iRows]; 
         if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
         {
            // Allocate and assign common data storage array.
            (*pppArray)[0] = new T [iRows * iColumns]; 
            if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
            {
               // Using pointer arithmetic requires the least overhead. There is no 
               // expensive repeated multiplication involved and very little additional 
               // memory is used for temporary variables.
               T** l_ppRow = (*pppArray);
               T* l_pRowFirstElement = l_ppRow[0];
               for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
               {
                  l_ppRow++;
                  l_pRowFirstElement += iColumns;
                  l_ppRow[0] = l_pRowFirstElement;
               }
               l_bResult = true;
            }
         }
      }
   }
}

Чтобы отменить выделение памяти, созданной с помощью вышеупомянутой утилиты, нужно просто отменить выделение в обратном порядке.

///
/// Matrix De-Allocator Utility
/// @param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// @return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
   bool l_bResult = false;
   if (pppArray != 0) // Test if pointer holds a valid address.
   {
      if ((*pppArray) != 0) // Test if pointer array was assigned.
      {
         if ((*pppArray)[0] != 0) // Test if data array was assigned.
         {
               // De-allocate common storage array.
               delete [] (*pppArray)[0];
            }
         }
         // De-allocate pointer array.
         delete [] (*pppArray);
         (*pppArray) = 0;
         l_bResult = true;
      }
   }
}

Использовать эти вышеупомянутые шаблонные функции очень просто (например,):

   .
   .
   .
   double l_ppMatrix = 0;
   NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
   .
   .
   .
   DeleteMatrix(&l_ppMatrix);
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;

Вот самый понятный & amp; Интуитивно понятный способ выделить динамический 2d массив в C ++. Шаблон в этом примере охватывает все случаи.

template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
    M = new T*[rows];
    for (int i = 0; i < rows; i++){
        M[i] = new T[cols];
    }
    return M;
}

... 

int main()
{
    ...
    int** M1 = matrixAllocate<int>(rows, cols, M1);
    double** M2 = matrixAllocate(rows, cols, M2);
    ...
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top