Question

Comment allouer dynamiquement une matrice 2D en C ++? J'ai essayé sur la base de ce que je sais déjà:

#include <iostream>

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

Cela fonctionne pour un paramètre, mais maintenant pour deux. Que dois-je faire?

Était-ce utile?

La solution

Une matrice est en réalité un tableau de tableaux.

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

Bien sûr, pour supprimer la matrice, procédez comme suit:

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

Je viens de découvrir une autre 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;
}

Libérer ce tableau est plus simple:

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

Cette solution présente l’avantage d’allouer un seul gros bloc de mémoire pour tous les éléments, au lieu de plusieurs petits morceaux. La première solution que j'ai publiée est un meilleur exemple du concept des tableaux de tableaux .

Autres conseils

Vous pouvez également utiliser std::vectors pour y parvenir:

en utilisant std::vector< std::vector<int> >

Exemple:

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

}

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

Si cela ne vous dérange pas, la syntaxe

arr[row * cols + col] = Aij;

ou utilisez l'opérateur [] en surchargeant quelque part. Cela peut être plus convivial en cache qu'un tableau de tableaux, ou peut-être pas, plus probablement, vous ne devriez pas vous en soucier. Je veux juste souligner que a) le tableau de tableaux n'est pas seulement une solution, b) certaines opérations sont plus faciles à mettre en œuvre si la matrice est située dans un bloc de mémoire. Ex.

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

une ligne plus courte que

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

bien que l'ajout de lignes à une telle matrice soit plus pénible

ou vous pouvez simplement allouer un tableau 1D mais référencer des éléments de façon 2D:

pour adresser la rangée 2, colonne 3 (le coin supérieur gauche est la rangée 0, la colonne 0):

arr [2 * MATRIX_WIDTH + 3]

où MATRIX_WIDTH est le nombre d'éléments d'une ligne.

L'autre réponse décrivant les tableaux de tableaux est correcte.
MAIS si vous envisagez de faire quelque chose de mathématique avec les tableaux - ou si vous avez besoin de quelque chose de spécial comme des matrices éparses, vous devriez regarder l’une des nombreuses librairies de maths comme TNT avant de réinventer trop de roues

J'ai cette classe de grille qui peut être utilisée comme une matrice simple si vous n'avez pas besoin d'opérateurs mathématiques.

/**
 * 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’utilisation du pointeur double est de loin le meilleur compromis entre vitesse d’exécution / optimisation et lisibilité. Utiliser un seul tableau pour stocker le contenu de la matrice est en réalité ce que fait un double pointeur.

J'ai utilisé avec succès la fonction de créateur basée sur un modèle (oui, je sais que j'utilise l'ancien référencement de pointeur de style C, mais le code est plus clair du côté appelant en ce qui concerne la modification des paramètres. pas possible avec des références, vous verrez ce que je veux dire):

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

Pour désaffecter la mémoire créée à l'aide de l'utilitaire susmentionné, il suffit de désaffecter en sens inverse.

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

Utiliser ces fonctions de modèle susmentionnées est alors très simple (par exemple):

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

Voici le plus clair & amp; façon intuitive je sais pour allouer un tableau dynamique 2d en C ++. Les exemples dans cet exemple couvrent tous les cas.

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);
    ...
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top