web-dev-qa-db-fra.com

Tableau bidimensionnel dynamique point à point

Première minuterie sur ce site, alors allez-y ..

Je suis un novice en C++ et je travaille actuellement sur le livre "Structures de données en C++, 2e éd, de D.S. Malik". 

Dans le livre, Malik propose deux manières de créer un tableau dynamique à deux dimensions. Dans la première méthode, vous déclarez une variable comme étant un tableau de pointeurs, chaque pointeur étant de type entier. ex.

int *board[4];

..et utilisez ensuite une boucle for pour créer les "colonnes" tout en utilisant le tableau de pointeurs comme "lignes".

La deuxième méthode consiste à utiliser un pointeur sur un pointeur.

int **board;
board = new int* [10]; 

etc.

Ma question est la suivante: quelle est la meilleure méthode? La méthode ** est plus facile à visualiser pour moi, mais la première méthode peut être utilisée de la même manière. Les deux méthodes peuvent être utilisées pour créer des tableaux 2D dynamiques. 

Edit: N'était pas assez clair avec le post ci-dessus. Voici un code que j'ai essayé:

int row, col;

cout << "Enter row size:";
cin >> row;
cout << "\ncol:";
cin >> col;

int *p_board[row];
for (int i=0; i < row; i++)
    p_board[i] = new int[col];

for (int i=0; i < row; i++)
{
    for (int j=0; j < col; j++)
    {
        p_board[i][j] = j;
        cout << p_board[i][j] << " ";
    }
    cout << endl;
}
cout << endl << endl;

int **p_p_board;
p_p_board = new int* [row];
for (int i=0; i < row; i++)
    p_p_board[i] = new int[col];

for (int i=0; i < row; i++)
{
    for (int j=0; j < col; j++)
    {
        p_p_board[i][j] = j;
        cout << p_p_board[i][j] << " ";
    }
    cout << endl;
}
20
user2280041

La première méthode ne peut pas être utilisée pour créer des tableaux dynamiques 2D parce que:

int *board[4];

vous avez essentiellement alloué un tableau de 4 pointeurs à intsur pile. Par conséquent, si vous remplissez maintenant chacun de ces 4 pointeurs avec un tableau dynamique:

for (int i = 0; i < 4; ++i) {
  board[i] = new int[10];
}

vous obtenez un tableau 2D avec statique nombre de lignes (dans ce cas 4) et dynamique nombre de colonnes (dans ce cas 10). Donc, ce n'est pas entièrement dynamique car, lorsque vous allouez un tableau sur une pile, vous spécifiez un devrait, un {taille constante} _, c'est-à-dire connu à heure de compilation. _. Le tableau dynamique s'appelle dynamique parce que sa taille ne doit pas nécessairement être connue à compilation, mais peut plutôt être déterminée par une variable dans runtime.

Encore une fois, quand vous faites:

int *board[4];

ou:

const int x = 4; // <--- `const` qualifier is absolutely needed in this case!
int *board[x];

vous fournissez une constante connue à compilation (dans ce cas, 4 ou x) de sorte que le compilateur puisse maintenant pré-allouer cette mémoire pour votre tableau, et lorsque votre programme est chargé dans la mémoire qu'il aurait déjà cette quantité de mémoire pour le tableau board, c'est pourquoi on l'appelle statique, c'est-à-dire parce que la taille est codée en dur} et ne peut pas être changée dynamiquement (en cours d'exécution).

D'autre part, quand vous faites:

int **board;
board = new int*[10];

ou:

int x = 10; // <--- Notice that it does not have to be `const` anymore!
int **board;
board = new int*[x];

le compilateur ne sait pas combien de mémoire le tableau board nécessitera et par conséquent, il ne fait rien pré-allouer. Mais lorsque vous démarrez votre programme, la taille du tableau serait déterminée par la valeur de la variable x (au moment de l'exécution) et l'espace correspondant pour le tableau board serait alloué sur ce que l'on appelle heap - la zone de mémoire. où tous les programmes en cours d'exécution sur votre ordinateur peuvent allouer inconnu au préalable _ (au moment de la compilation) quantité de mémoire pour un usage personnel.

En conséquence, pour créer réellement un tableau 2D dynamique, vous devez utiliser la deuxième méthode:

int **board;
board = new int*[10]; // dynamic array (size 10) of pointers to int

for (int i = 0; i < 10; ++i) {
  board[i] = new int[10];
  // each i-th pointer is now pointing to dynamic array (size 10) of actual int values
}

Nous venons de créer un tableau 2D carré de 10 sur 10 dimensions. Pour le parcourir et le renseigner avec les valeurs réelles, par exemple 1, nous pourrions utiliser des boucles imbriquées:

for (int i = 0; i < 10; ++i) {   // for each row
  for (int j = 0; j < 10; ++j) { // for each column
    board[i][j] = 1;
  }
}
39
Alexander Shukaev

Ce que vous décrivez pour la deuxième méthode ne vous donne qu'un tableau 1D:

int *board = new int[10];

Cela alloue juste un tableau avec 10 éléments. Peut-être que vous vouliez dire quelque chose comme ça:

int **board = new int*[4];
for (int i = 0; i < 4; i++) {
  board[i] = new int[10];
}

Dans ce cas, nous allouons 4 int*s, puis nous faisons pointer chacun de ces points vers un tableau alloué dynamiquement de 10 ints.

Alors maintenant, nous comparons cela avec int* board[4];. La principale différence est que lorsque vous utilisez un tableau comme celui-ci, le nombre de "lignes" doit être connu au moment de la compilation. En effet, les tableaux doivent avoir des tailles fixes au moment de la compilation. Vous pouvez également avoir un problème si vous souhaitez peut-être renvoyer ce tableau de int*s, car le tableau sera détruit à la fin de sa portée.

La méthode d'allocation dynamique des lignes et des colonnes nécessite des mesures plus complexes pour éviter les fuites de mémoire. Vous devez désallouer la mémoire comme ceci:

for (int i = 0; i < 4; i++) {
  delete[] board[i];
}
delete[] board;

Je dois recommander l'utilisation d'un conteneur standard à la place. Vous voudrez peut-être utiliser un std::array<int, std::array<int, 10> 4> ou peut-être un std::vector<std::vector<int>> que vous initialiserez à la taille appropriée.

5
Joseph Mansfield

Dans les deux cas, votre dimension interne peut être spécifiée dynamiquement (c'est-à-dire extraite d'une variable), mais la différence réside dans la dimension externe.

Cette question est fondamentalement équivalente à la suivante:

int* x = new int[4]; est-il "meilleur" que int x[4]?

La réponse est: " non , sauf si vous devez choisir cette dimension de tableau de manière dynamique."

Ce code fonctionne bien avec très peu d'exigences sur les bibliothèques externes et montre une utilisation de base de int **array.

Cette réponse montre que chaque tableau est dimensionné de manière dynamique, ainsi que la façon d'assigner un tableau feuille de taille dynamique dans le tableau de branche de taille dynamique.

Ce programme prend les arguments de STDIN au format suivant:

2 2   
3 1 5 4
5 1 2 8 9 3
0 1
1 3

Code du programme ci-dessous ...

#include <iostream>

int main()
{
    int **array_of_arrays;

    int num_arrays, num_queries;
    num_arrays = num_queries = 0;
    std::cin >> num_arrays >> num_queries;
    //std::cout << num_arrays << " " << num_queries;

    //Process the Arrays
    array_of_arrays = new int*[num_arrays];
    int size_current_array = 0;

    for (int i = 0; i < num_arrays; i++)
    {
        std::cin >> size_current_array;
        int *tmp_array = new int[size_current_array];
        for (int j = 0; j < size_current_array; j++)
        {
            int tmp = 0;
            std::cin >> tmp;
            tmp_array[j] = tmp;
        }
        array_of_arrays[i] = tmp_array;
    }


    //Process the Queries
    int x, y;
    x = y = 0;
    for (int q = 0; q < num_queries; q++)
    {
        std::cin >> x >> y;
        //std::cout << "Current x & y: " << x << ", " << y << "\n";
        std::cout << array_of_arrays[x][y] << "\n";
    }

    return 0;
}

C'est une implémentation très simple de int main qui repose uniquement sur std::cin et std::cout. Barebones, mais assez bon pour montrer comment travailler avec des tableaux multidimensionnels simples.

0
Andrew