2009-09-10 9 views
13

Come si assegna dinamicamente una matrice 2D in C++? Ho provato sulla base di quello che già so:Come si assegna dinamicamente una matrice?

#include <iostream> 

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

Si lavora per un parametro, ma ora per due. Cosa dovrei fare?

+0

stato fatto più e più volte: http://stackoverflow.com/questions/365782/how -do-i-best-handle-dynamic-multi-dimensional-array-in-cc http://stackoverflow.com/questions/527887/cc-optimize-data-structures-array-of-arrays-or-just- array e altri – dmckee

risposta

41

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 cancellare la matrice, si dovrebbe effettuare le seguenti operazioni:

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

ho appena capito 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; 
} 

liberando questo array è più semplice:

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

Questa soluzione ha il vantaggio di allocare un unico grande blocco di memoria per tutti gli elementi, invece di alcuni piccoli pezzi. La prima soluzione che ho postato è un esempio migliore degli array degli array.

+0

Questa non è una cattiva idea. Ha l'ovvio vantaggio di mantenere la localizzazione della cache mantenendo la sintassi dell'array multidimensionale. Mi piace. – greyfade

+0

Non avevo proprio idea di come scrivere in C++ allora ... – pyon

+0

Preferirei il primo, per chiarezza. –

2
#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; 
    } 
1

oppure si può semplicemente assegnare a 1D elementi dell'array ma di riferimento in modo 2D:

di indirizzo di riga 2, colonna 3 (angolo superiore sinistro è riga 0, colonna 0):

arr [2 * MATRIX_WIDTH + 3]

dove MATRIX_WIDTH è il numero di elementi di una riga.

+0

Perché dovresti provare a modificare un array bidimensionale quando è perfettamente facile creare un vero array bidimensionale? –

+1

perché è possibile accedere in modo bidimensionale alla cache in modo amichevole quando le prestazioni sono davvero fondamentali – DeusAduro

+0

Ancora meglio: allocare un array 1D di elementi e un altro array 1D di puntatori al primo elemento di ogni riga. – pyon

1
arr = new int[cols*rows]; 

Se uno non si mente sintassi

arr[row * cols + col] = Aij; 

o gestore uso [] overaloading da qualche parte. Questo potrebbe essere più facile da usare rispetto alla cache dell'array, o potrebbe non esserlo, più probabilmente non dovresti preoccupartene. Voglio solo sottolineare che a) l'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 esempio.

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

una linea di lunghezza inferiore

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

se l'aggiunta di righe di tale matrice è più dolorosa

21

È anche possibile utilizzare std::vectors per raggiungere questo:

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

} 
+2

+1 per l'utilizzo di std :: vector. Io non uso troppo il STL da solo, ma è perché sono un masochista quando si tratta di gestione della memoria. L'utilizzo dell'STL è molto meno incline agli errori. – pyon

+0

Mentre funziona, ha un overhead manuale ripetuto. Sei una classe preparata (ce ne sono molti) o avvolgi gli array n-dimensionali in stile c in una classe di tua invenzione. – dmckee

+6

Invece di ridimensionarlo, basta costruirlo con la dimensione corretta. 'int m = 10, n = 4; std :: vector > a (m, std :: vector (n, 0)); ' – TimW

14

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

+1 per l'utilizzo di Boost, ma l'utilizzo di tale libreria dipende da quanto è buono il compilatore che si usa è in ottimizzando il tuo codice. – pyon

0

L'altra risposta descrivono array di array siano corrette.
MA se si sta progettando di fare un qualcosa di matematica con gli array - o hai bisogno di qualcosa di speciale come matrici sparse che si dovrebbe guardare uno dei tanti librerie matematica come TNT prima di ri-inventare troppe ruote

0

ho questa griglia classe che può essere usata come una matrice semplice 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; 
} 
0

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

Ho usato con successo la seguente funzione di creazione di modelli (sì, so di usare il vecchio puntatore di stile C che fa riferimento, ma rende il codice più chiaro sul lato chiamante per quanto riguarda i parametri di modifica - qualcosa che mi piace dei puntatori che non è possibile con i riferimenti vedrete 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 de-allocare la memoria creata utilizzando l'utilità di cui sopra, si deve semplicemente a de-allocare in senso inverso.

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

Per utilizzare queste funzioni modello di cui sopra è quindi molto semplice (ad esempio):

. 
    . 
    . 
    double l_ppMatrix = 0; 
    NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix. 
    . 
    . 
    . 
    DeleteMatrix(&l_ppMatrix); 
0
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; 
+1

Alcune spiegazioni sarebbero semplicemente perfette! ;) – mrt

Problemi correlati