web-dev-qa-db-fra.com

Comment allouer dynamiquement une matrice?

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 devrais-je faire?

16
chustar

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

La libération de ce tableau est plus facile:

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

Cette solution présente l'avantage d'allouer un seul grand 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 des tableaux de tableaux concept, cependant.

44
pyon

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

}
23
aJ.

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] ;
}
14
yoco
 #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;
     }
3
adatapost
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 pour le 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) un 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. Par exemple.

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 douloureux

3
maykeye

ou vous pouvez simplement allouer un tableau 1D mais référencer des éléments de manière 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.

1
DmitryK
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;
0
sballot

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.

0
Martin Beckett

L'utilisation du double pointeur 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 cela rend le code plus clair du côté appelant en ce qui concerne la modification des paramètres. 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ésallouer 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 les 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);
0
Rufus Neethling

Voici la méthode la plus claire et la plus intuitive que je connaisse pour allouer un tableau 2D dynamique en C++. Le modèle dans cet exemple couvre 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);
    ...
}
0
Nik-Lz

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