Domanda

Come si assegna dinamicamente una matrice 2D in C ++? Ho provato in base a ciò che già conosco:

#include <iostream>

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

Funziona per un parametro, ma ora per due. Cosa devo fare?

È stato utile?

Soluzione

Una matrice è in realtà una matrice di matrici.

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

Naturalmente, per eliminare la matrice, dovresti fare quanto segue:

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

Ho appena scoperto un'altra possibilità:

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

Liberare questo array è più semplice:

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

Questa soluzione ha il vantaggio di allocare un singolo grande blocco di memoria per tutti gli elementi, anziché diversi piccoli pezzi. La prima soluzione che ho pubblicato è un esempio migliore del concetto matrici di matrici ,

Altri suggerimenti

Puoi anche usare std::vectors per raggiungere questo obiettivo:

utilizzando std::vector< std::vector<int> >

Esempio:

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

}

Prova 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];

Se non ti dispiace sintassi

arr[row * cols + col] = Aij;

o usa l'operatore [] in eccesso da qualche parte. Questo potrebbe essere più adatto alla cache rispetto alla matrice di array o potrebbe non esserlo, molto probabilmente non dovresti preoccupartene. Voglio solo sottolineare che a) un array di array non è solo una soluzione, b) alcune operazioni sono più facili da implementare se la matrice si trova in un blocco di memoria. Per es.

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

una riga più corta di

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

sebbene l'aggiunta di righe a tale matrice sia più dolorosa

oppure puoi semplicemente allocare un array 1D ma fai riferimento a elementi in modo 2D:

per indirizzare la riga 2, colonna 3 (l'angolo in alto a sinistra è la riga 0, colonna 0):

arr [2 * MATRIX_WIDTH + 3]

dove MATRIX_WIDTH è il numero di elementi in una riga.

L'altra risposta che descrive gli array di array è corretta.
MA se hai intenzione di fare qualcosa di matematico con gli array - o hai bisogno di qualcosa di speciale come matrici sparse, dovresti guardare una delle tante librerie matematiche come TNT prima di reinventare troppe ruote

Ho questa classe di griglia che può essere usata come una semplice matrice se non hai bisogno di operatori matematici.

/**
 * 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;
}

L'uso del doppio puntatore è di gran lunga il miglior compromesso tra velocità / ottimizzazione dell'esecuzione e leggibilità. L'utilizzo di un singolo array per archiviare i contenuti della matrice è in realtà ciò che fa un doppio puntatore.

Ho usato con successo la seguente funzione di creazione del modello (sì, lo so che uso il vecchio riferimento al puntatore in stile C, ma rende il codice più chiaro sul lato chiamante per quanto riguarda la modifica dei parametri - qualcosa che mi piace dei puntatori che è impossibile con i riferimenti. Vedrai cosa intendo):

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

Per disallocare la memoria creata usando l'utilità sopra menzionata, si deve semplicemente disallocare al contrario.

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

Utilizzare queste funzioni modello sopra menzionate è quindi molto semplice (ad es.):

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

Ecco l'ampli & più chiaro; modo intuitivo che conosco per allocare un array 2D dinamico in C ++. Il modello in questo esempio copre tutti i casi.

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);
    ...
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top