web-dev-qa-db-fra.com

Comment déclarer un tableau 2D en C++ en utilisant new?

Comment déclarer un tableau 2d utilisant new?

Comme pour un tableau "normal", je voudrais:

int* ary = new int[Size]

mais

int** ary = new int[sizeY][sizeX]

a) ne fonctionne pas/compile et b) n'accomplit pas ce qui:

int ary[sizeY][sizeX] 

est-ce que.

447
user20844

Un tableau 2D dynamique est fondamentalement un tableau de pointeurs vers des tableaux . Vous pouvez l'initialiser en utilisant une boucle, comme ceci:

int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
    a[i] = new int[colCount];

Ce qui précède, pour colCount= 5 et rowCount = 4, produira ce qui suit:

enter image description here

657
Mehrdad Afshari
int** ary = new int[sizeY][sizeX]

devrait être:

int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
    ary[i] = new int[sizeX];
}

et puis nettoyer serait:

for(int i = 0; i < sizeY; ++i) {
    delete [] ary[i];
}
delete [] ary;

EDIT: comme Dietrich Epp l’a souligné dans ses commentaires, il ne s’agit pas d’une solution légère. Une autre approche consisterait à utiliser un seul gros bloc de mémoire:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]
279
Kevin Loney

Bien que cette réponse populaire vous fournisse la syntaxe d’indexation que vous souhaitez, elle est doublement inefficace: grande et lente, dans l’espace et dans le temps. Il y a un meilleur moyen.

_ {Pourquoi cette réponse est grande et lente} _

La solution proposée consiste à créer un tableau dynamique de pointeurs, puis à initialiser chaque pointeur sur son propre tableau dynamique indépendant. Le avantage de cette approche est qu'il vous donne la syntaxe d'indexation à laquelle vous êtes habitué. Si vous voulez trouver la valeur de la matrice à la position x, y, vous dites:

int val = matrix[ x ][ y ];

Cela fonctionne car matrix [x] renvoie un pointeur sur un tableau, qui est ensuite indexé avec [y]. Le décomposer:

int* row = matrix[ x ];
int  val = row[ y ];

Pratique, oui? Nous aimons notre syntaxe [x] [y]. 

Mais la solution a un gros {désavantage} _, c'est-à-dire qu'elle est à la fois grosse et lente. 

Pourquoi?

La raison pour laquelle c'est à la fois gros et lent est en fait la même. Chaque "ligne" de la matrice est un tableau dynamique alloué séparément. Faire une allocation de tas coûte cher à la fois en temps et en espace. L'allocateur met du temps à faire l'allocation, exécutant parfois des algorithmes O(n) pour le faire. Et l’allocateur "tamponne" chacune de vos matrices de lignes avec des octets supplémentaires pour la comptabilité et l’alignement. Cet espace supplémentaire coûte ... bien ... un espace supplémentaire. Le désallocateur prendra également davantage de temps lorsque vous allez désallouer la matrice, libérant minutieusement chaque allocation de ligne. Ca me transpire juste d'y penser.

Il y a une autre raison pour laquelle c'est lent. Ces allocations séparées ont tendance à vivre dans des parties discontinues de la mémoire. Une rangée peut être à l'adresse 1 000, une autre à l'adresse 100 000 - vous voyez l'idée. Cela signifie que lorsque vous parcourez la matrice, vous traversez la mémoire comme une personne sauvage. Cela a tendance à entraîner des erreurs de mémoire cache qui ralentissent considérablement votre temps de traitement.

Donc, si vous devez absolument avoir votre jolie syntaxe d'indexation [x] [y], utilisez cette solution. Si vous voulez la rapidité et la petite taille (et si vous ne vous en souciez pas, pourquoi travaillez-vous en C++?), Vous avez besoin d'une solution différente.

_ {Une solution différente} _

La meilleure solution consiste à allouer l’ensemble de votre matrice sous la forme d’un tableau dynamique unique, puis à utiliser vos mathématiques (légèrement) intelligentes d’indexation pour accéder aux cellules. L'indexation mathématique n'est que très légèrement intelligente; non, ce n'est pas intelligent du tout: c'est évident.

class Matrix
{
    ...
    size_t index( int x, int y ) const { return x + m_width * y; }
};

Étant donné cette fonction index() (dont j'imagine qu'elle est membre d'une classe car elle doit connaître le m_width de votre matrice), vous pouvez accéder aux cellules de votre matrice. Le tableau de matrice est alloué comme ceci:

array = new int[ width * height ];

Donc, l'équivalent de ceci dans la solution lente et grasse:

array[ x ][ y ]

... est-ce dans la petite solution rapide:

array[ index( x, y )]

Triste, je sais. Mais vous vous y habituerez. Et votre processeur vous en sera reconnaissant.

178
OldPeculier

En C++ 11, il est possible:

auto array = new double[M][N]; 

De cette façon, la mémoire n'est pas initialisée. Pour l'initialiser, faites ceci à la place:

auto array = new double[M][N]();

Exemple de programme (compiler avec "g ++ -std = c ++ 11"):

#include <iostream>
#include <utility>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;

int main()
{
    const auto M = 2;
    const auto N = 2;

    // allocate (no initializatoin)
    auto array = new double[M][N];

    // pollute the memory
    array[0][0] = 2;
    array[1][0] = 3;
    array[0][1] = 4;
    array[1][1] = 5;

    // re-allocate, probably will fetch the same memory block (not portable)
    delete[] array;
    array = new double[M][N];

    // show that memory is not initialized
    for(int r = 0; r < M; r++)
    {
        for(int c = 0; c < N; c++)
            cout << array[r][c] << " ";
        cout << endl;
    }
    cout << endl;

    delete[] array;

    // the proper way to zero-initialize the array
    array = new double[M][N]();

    // show the memory is initialized
    for(int r = 0; r < M; r++)
    {
        for(int c = 0; c < N; c++)
            cout << array[r][c] << " ";
        cout << endl;
    }

    int info;
    cout << abi::__cxa_demangle(typeid(array).name(),0,0,&info) << endl;

    return 0;
}

Sortie:

2 4 
3 5 

0 0 
0 0 
double (*) [2]
104
M. Alaggan

Je suppose que dans votre exemple de tableau statique, vous voulez un tableau rectangulaire et non un tableau irrégulier. Vous pouvez utiliser les éléments suivants:

int *ary = new int[sizeX * sizeY];

Ensuite, vous pouvez accéder aux éléments en tant que:

ary[y*sizeX + x]

N'oubliez pas d'utiliser delete [] sur ary.

52
Dan Ellis

Il existe deux techniques générales que je recommanderais pour cela en C++ 11 et supérieur, une pour les dimensions de compilation et une pour le temps d'exécution. Les deux réponses supposent que vous voulez des tableaux uniformes et bidimensionnels (pas des tableaux dentelés).

Compiler les dimensions du temps

Utilisez un std::array sur std::array, puis utilisez new pour le placer sur le tas:

// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;

Encore une fois, cela ne fonctionne que si les tailles des dimensions sont connues au moment de la compilation.

Dimensions d'exécution

La meilleure façon de réaliser un tableau à 2 dimensions avec des tailles uniquement connues au moment de l'exécution est de l'envelopper dans une classe. La classe allouera un tableau 1d puis surcharge operator [] pour fournir l'indexation de la première dimension. Cela fonctionne car en C++, un tableau 2D est row-major:

  matrix shown in logical form and one-dimensional form

(Extrait de http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )

Une séquence de mémoire contiguë est bonne pour des raisons de performances et est également facile à nettoyer. Voici un exemple de classe qui omet beaucoup de méthodes utiles mais montre l'idée de base:

#include <memory>

class Grid {
  size_t _rows;
  size_t _columns;
  std::unique_ptr<int[]> data;

public:
  Grid(size_t rows, size_t columns)
      : _rows{rows},
        _columns{columns},
        data{std::make_unique<int[]>(rows * columns)} {}

  size_t rows() const { return _rows; }

  size_t columns() const { return _columns; }

  int *operator[](size_t row) { return row * _columns + data.get(); }

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }
}

Nous créons donc un tableau avec des entrées std::make_unique<int[]>(rows * columns). Nous surchargeons operator [] qui indexera la ligne pour nous. Il retourne un int * qui pointe au début de la ligne, ce qui peut ensuite être déréférencé comme d'habitude pour la colonne. Notez que make_unique est d'abord livré en C++ 14, mais vous pouvez le polyfiller en C++ 11 si nécessaire.

Il est également courant que ces types de structures surchargent operator():

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }

Techniquement, je n'ai pas utilisé new ici, mais il est facile de passer de std::unique_ptr<int[]> à int * et d'utiliser new/delete.

41
Levi Morrison

Cette question me dérangeait - c'est un problème assez commun pour qu'une bonne solution existe déjà, quelque chose de mieux que le vecteur de vecteurs ou le fait d'indexer son propre tableau.

Quand quelque chose doit exister en C++ mais n’existe pas, le premier endroit à regarder est boost.org . J'ai trouvé la Boost Multidimensional Array Library, multi_array . Il inclut même une classe multi_array_ref qui peut être utilisée pour envelopper votre propre tampon de tableau unidimensionnel.

26
Mark Ransom

Pourquoi ne pas utiliser STL: vector? Si facile, et vous n'avez pas besoin de supprimer le vecteur.

int rows = 100;
int cols = 200;
vector< vector<int> > f(rows, vector<int>(cols));
f[rows - 1][cols - 1] = 0; // use it like arrays

Source: Comment créer 2, 3 (ou multi) tableaux multidimensionnels en C/C++?

23
justyy

Comment allouer un tableau multidimensionnel contigu dans GNU C++? Il existe une extension GNU qui permet à la syntaxe "standard" de fonctionner.

Il semble que le problème vienne de l'opérateur new []. Assurez-vous d'utiliser l'opérateur new à la place:

double (* in)[n][n] = new (double[m][n][n]);  // GNU extension

Et c'est tout: vous obtenez un tableau multidimensionnel compatible C.

14
etham

typedef est ton ami

Après avoir parcouru de nombreuses autres réponses, j’ai trouvé qu’une explication plus approfondie était nécessaire, car beaucoup d’autres réponses souffraient de problèmes de performances ou vous obligeaient à utiliser une syntaxe inhabituelle ou fastidieuse pour déclarer le tableau ou accéder au tableau. éléments (ou tout ce qui précède).

Premièrement, cette réponse suppose que vous connaissiez les dimensions du tableau au moment de la compilation. Si tel est le cas, il s'agit de la meilleure solution car elle donnera à la fois les meilleures performances et vous permettra d'utiliser la syntaxe de tableau standard pour accéder aux éléments du tableau

Cela donne les meilleures performances car toutes les baies sont allouées sous forme de bloc de mémoire contigu, ce qui signifie que vous aurez probablement moins de pages manquantes et une meilleure localité spatiale. L'allocation dans une boucle peut entraîner la dispersion des baies sur plusieurs pages non contiguës dans la mémoire virtuelle, car la boucle d'allocation peut être interrompue (éventuellement plusieurs fois) par d'autres threads ou processus, ou simplement par la discrétion du allocator remplissant de petits blocs de mémoire vides disponibles. 

Les autres avantages sont une syntaxe de déclaration simple et une syntaxe d'accès au tableau standard.

En C++ en utilisant new:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (array5k_t)[5000];

array5k_t *array5k = new array5k_t[5000];

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}

Ou style C utilisant calloc:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

typedef double (*array5k_t)[5000];

array5k_t array5k = calloc(5000, sizeof(double)*5000);

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}
12
Robert S. Barnes

Un tableau 2D est essentiellement un tableau 1D de pointeurs, chaque pointeur pointant vers un tableau 1D, qui contiendra les données réelles.

Ici, N est la ligne et M est la colonne.

allocation dynamique

int** ary = new int*[N];
  for(int i = 0; i < N; i++)
      ary[i] = new int[M];

remplir

for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
      ary[i][j] = i;

impression

for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
      std::cout << ary[i][j] << "\n";

libre

for(int i = 0; i < N; i++)
    delete [] ary[i];
delete [] ary;
12
akshay_rahar

Ce problème me préoccupe depuis 15 ans et toutes les solutions fournies ne me convenaient pas. Comment créer un tableau multidimensionnel dynamique de manière contiguë en mémoire? Aujourd'hui, j'ai enfin trouvé la réponse. En utilisant le code suivant, vous pouvez le faire:

#include <iostream>

int main(int argc, char** argv)
{
    if (argc != 3)
    {
        std::cerr << "You have to specify the two array dimensions" << std::endl;
        return -1;
    }

    int sizeX, sizeY;

    sizeX = std::stoi(argv[1]);
    sizeY = std::stoi(argv[2]);

    if (sizeX <= 0)
    {
        std::cerr << "Invalid dimension x" << std::endl;
        return -1;
    }
    if (sizeY <= 0)
    {
        std::cerr << "Invalid dimension y" << std::endl;
        return -1;
    }

    /******** Create a two dimensional dynamic array in continuous memory ******
     *
     * - Define the pointer holding the array
     * - Allocate memory for the array (linear)
     * - Allocate memory for the pointers inside the array
     * - Assign the pointers inside the array the corresponding addresses
     *   in the linear array
     **************************************************************************/

    // The resulting array
    unsigned int** array2d;

    // Linear memory allocation
    unsigned int* temp = new unsigned int[sizeX * sizeY];

    // These are the important steps:
    // Allocate the pointers inside the array,
    // which will be used to index the linear memory
    array2d = new unsigned int*[sizeY];

    // Let the pointers inside the array point to the correct memory addresses
    for (int i = 0; i < sizeY; ++i)
    {
        array2d[i] = (temp + i * sizeX);
    }



    // Fill the array with ascending numbers
    for (int y = 0; y < sizeY; ++y)
    {
        for (int x = 0; x < sizeX; ++x)
        {
            array2d[y][x] = x + y * sizeX;
        }
    }



    // Code for testing
    // Print the addresses
    for (int y = 0; y < sizeY; ++y)
    {
        for (int x = 0; x < sizeX; ++x)
        {
            std::cout << std::hex << &(array2d[y][x]) << ' ';
        }
    }
    std::cout << "\n\n";

    // Print the array
    for (int y = 0; y < sizeY; ++y)
    {
        std::cout << std::hex << &(array2d[y][0]) << std::dec;
        std::cout << ": ";
        for (int x = 0; x < sizeX; ++x)
        {
            std::cout << array2d[y][x] << ' ';
        }
        std::cout << std::endl;
    }



    // Free memory
    delete[] array2d[0];
    delete[] array2d;
    array2d = nullptr;

    return 0;
}

Lorsque vous appelez le programme avec les valeurs sizeX = 20 et sizeY = 15, le résultat sera le suivant:

0x603010 0x603014 0x603018 0x60301c 0x603020 0x603024 0x603028 0x60302c 0x603030 0x603034 0x603038 0x60303c 0x603040 0x603044 0x603048 0x60304c 0x603050 0x603054 0x603058 0x60305c 0x603060 0x603064 0x603068 0x60306c 0x603070 0x603074 0x603078 0x60307c 0x603080 0x603084 0x603088 0x60308c 0x603090 0x603094 0x603098 0x60309c 0x6030a0 0x6030a4 0x6030a8 0x6030ac 0x6030b0 0x6030b4 0x6030b8 0x6030bc 0x6030c0 0x6030c4 0x6030c8 0x6030cc 0x6030d0 0x6030d4 0x6030d8 0x6030dc 0x6030e0 0x6030e4 0x6030e8 0x6030ec 0x6030f0 0x6030f4 0x6030f8 0x6030fc 0x603100 0x603104 0x603108 0x60310c 0x603110 0x603114 0x603118 0x60311c 0x603120 0x603124 0x603128 0x60312c 0x603130 0x603134 0x603138 0x60313c 0x603140 0x603144 0x603148 0x60314c 0x603150 0x603154 0x603158 0x60315c 0x603160 0x603164 0x603168 0x60316c 0x603170 0x603174 0x603178 0x60317c 0x603180 0x603184 0x603188 0x60318c 0x603190 0x603194 0x603198 0x60319c 0x6031a0 0x6031a4 0x6031a8 0x6031ac 0x6031b0 0x6031b4 0x6031b8 0x6031bc 0x6031c0 0x6031c4 0x6031c8 0x6031cc 0x6031d0 0x6031d4 0x6031d8 0x6031dc 0x6031e0 0x6031e4 0x6031e8 0x6031ec 0x6031f0 0x6031f4 0x6031f8 0x6031fc 0x603200 0x603204 0x603208 0x60320c 0x603210 0x603214 0x603218 0x60321c 0x603220 0x603224 0x603228 0x60322c 0x603230 0x603234 0x603238 0x60323c 0x603240 0x603244 0x603248 0x60324c 0x603250 0x603254 0x603258 0x60325c 0x603260 0x603264 0x603268 0x60326c 0x603270 0x603274 0x603278 0x60327c 0x603280 0x603284 0x603288 0x60328c 0x603290 0x603294 0x603298 0x60329c 0x6032a0 0x6032a4 0x6032a8 0x6032ac 0x6032b0 0x6032b4 0x6032b8 0x6032bc 0x6032c0 0x6032c4 0x6032c8 0x6032cc 0x6032d0 0x6032d4 0x6032d8 0x6032dc 0x6032e0 0x6032e4 0x6032e8 0x6032ec 0x6032f0 0x6032f4 0x6032f8 0x6032fc 0x603300 0x603304 0x603308 0x60330c 0x603310 0x603314 0x603318 0x60331c 0x603320 0x603324 0x603328 0x60332c 0x603330 0x603334 0x603338 0x60333c 0x603340 0x603344 0x603348 0x60334c 0x603350 0x603354 0x603358 0x60335c 0x603360 0x603364 0x603368 0x60336c 0x603370 0x603374 0x603378 0x60337c 0x603380 0x603384 0x603388 0x60338c 0x603390 0x603394 0x603398 0x60339c 0x6033a0 0x6033a4 0x6033a8 0x6033ac 0x6033b0 0x6033b4 0x6033b8 0x6033bc 0x6033c0 0x6033c4 0x6033c8 0x6033cc 0x6033d0 0x6033d4 0x6033d8 0x6033dc 0x6033e0 0x6033e4 0x6033e8 0x6033ec 0x6033f0 0x6033f4 0x6033f8 0x6033fc 0x603400 0x603404 0x603408 0x60340c 0x603410 0x603414 0x603418 0x60341c 0x603420 0x603424 0x603428 0x60342c 0x603430 0x603434 0x603438 0x60343c 0x603440 0x603444 0x603448 0x60344c 0x603450 0x603454 0x603458 0x60345c 0x603460 0x603464 0x603468 0x60346c 0x603470 0x603474 0x603478 0x60347c 0x603480 0x603484 0x603488 0x60348c 0x603490 0x603494 0x603498 0x60349c 0x6034a0 0x6034a4 0x6034a8 0x6034ac 0x6034b0 0x6034b4 0x6034b8 0x6034bc 

0x603010: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
0x603060: 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 
0x6030b0: 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 
0x603100: 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 
0x603150: 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
0x6031a0: 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 
0x6031f0: 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 
0x603240: 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 
0x603290: 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 
0x6032e0: 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 
0x603330: 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 
0x603380: 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 
0x6033d0: 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 
0x603420: 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 
0x603470: 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

Comme vous pouvez le constater, la matrice multidimensionnelle est contiguë en mémoire et aucune adresse mémoire ne se chevauche. Même la routine de libération du tableau est plus simple que la méthode standard d'allocation dynamique de mémoire pour chaque colonne (ou ligne, en fonction de l'affichage du tableau). Étant donné que le tableau consiste essentiellement en deux tableaux linéaires, seuls ces deux doivent être (et peuvent être) libérés.

Cette méthode peut être étendue à plus de deux dimensions avec le même concept. Je ne le ferai pas ici, mais lorsque vous avez une idée derrière cela, la tâche est simple.

J'espère que ce code vous aidera autant qu'il m'a aidé.

8
kamshi

Essayez de faire ceci:

int **ary = new int[sizeY];
for (int i = 0; i < sizeY; i++)
    ary[i] = new int[sizeX];
4
stanigator

Ici, j'ai deux options. La première montre le concept d'un tableau de tableaux ou d'un pointeur de pointeurs. Je préfère le second car les adresses sont contiguës, comme vous pouvez le voir sur l'image.

 enter image description here

#include <iostream>

using namespace std;


int main(){

    int **arr_01,**arr_02,i,j,rows=4,cols=5;

    //Implementation 1
    arr_01=new int*[rows];

    for(int i=0;i<rows;i++)
        arr_01[i]=new int[cols];

    for(i=0;i<rows;i++){
        for(j=0;j<cols;j++)
            cout << arr_01[i]+j << " " ;
        cout << endl;
    }


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


    cout << endl;
    //Implementation 2
    arr_02=new int*[rows];
    arr_02[0]=new int[rows*cols];
    for(int i=1;i<rows;i++)
        arr_02[i]=arr_02[0]+cols*i;

    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++)
            cout << arr_02[i]+j << " " ;
        cout << endl;
    }

    delete[] arr_02[0];
    delete[] arr_02;


    return 0;
}
2
Erick M

Commencez par définir le tableau à l'aide de pointeurs (ligne 1):

int** a = new int* [x];     //x is the number of rows
for(int i = 0; i < x; i++)
    a[i] = new int[y];     //y is the number of columns

Si votre projet est CLI (Common Language Runtime Support), alors:

Vous pouvez utiliser la classe array, pas celle que vous obtenez lorsque vous écrivez:

#include <array>
using namespace std;

En d'autres termes, vous n'obtenez pas la classe de tableau non managée lorsque vous utilisez l'espace de noms std et l'inclusion de l'en-tête de tableau, pas la classe de tableau non managée définie dans l'espace de nom std et dans l'en-tête de tableau, mais le tableau de classe gérée de la CLI.

avec cette classe, vous pouvez créer un tableau de n’importe quel rang de votre choix.

Le code suivant ci-dessous crée un nouveau tableau à deux dimensions de 2 lignes et 3 colonnes de type int, que je nomme "arr":

array<int, 2>^ arr = gcnew array<int, 2>(2, 3);

Vous pouvez maintenant accéder aux éléments du tableau, en le nommant et en écrivant un seul parenthèses carrées [] et, à l'intérieur, ajoutez la ligne et la colonne et séparez-les par la virgule ,.

Le code suivant ci-dessous accède à un élément de la deuxième ligne et de la première colonne du tableau que j'ai déjà créé dans le code précédent ci-dessus:

arr[0, 1]

écrire cette ligne uniquement pour lire la valeur de cette cellule, c’est-à-dire obtenir la valeur dans cette cellule, mais si vous ajoutez le signe égal =, vous êtes sur le point d’écrire la valeur dans cette cellule, c’est-à-dire, définissez la valeur dans cette celluleVous pouvez également utiliser les opérateurs + =, - =, * = et/= bien sûr, uniquement pour les nombres (int, float, double, __int16, __int32, __int64, etc.), mais vous le connaissez déjà.

Si votre projet est not CLI, vous pouvez utiliser la classe array non gérée de l'espace de noms std, si vous #include <array>, bien sûr, mais le problème est que cette classe est différente de celle du tableau CLI. Créer un tableau de ce type est identique à celui de la CLI, sauf que vous devrez supprimer le signe ^ et le mot clé gcnew. Mais malheureusement, le deuxième paramètre int dans les parenthèses <> spécifie la longueur (taille) du tableau, not son ​​rang!

Il n'y a aucun moyen de spécifier un rang dans ce type de tableau, rang est la fonctionnalité uniquement du tableau CLI..

le tableau std se comporte comme un tableau normal en c ++, que vous définissez avec un pointeur, par exemple int* et ensuite: new int[size], ou sans pointeur: int arr[size], mais contrairement au tableau normal du c ++, le tableau std fournit des fonctions que vous pouvez utiliser avec les éléments de le tableau, comme remplissage, début, fin, taille, etc., mais le tableau normal fournit rien.

Mais les tableaux std sont toujours des tableaux unidimensionnels, comme les tableaux c ++ normaux . Mais grâce aux solutions suggérées par les autres utilisateurs, vous pouvez adapter les mêmes idées à un tableau c ++ normal à un tableau bidimensionnel. à std tableau, par exemple selon l'idée de Mehrdad Afshari, nous pouvons écrire le code suivant:

array<array<int, 3>, 2> array2d = array<array<int, 3>, 2>();

Cette ligne de code crée un "jugged array", qui est un tableau à une dimension que chacune de ses cellules est ou pointe vers un autre tableau à une dimension.

Si tous les tableaux à une dimension d'un tableau à une dimension sont égaux en longueur/taille, vous pouvez traiter la variable array2d comme un tableau à deux dimensions réel. Vous pouvez également utiliser les méthodes spéciales pour traiter les lignes ou les colonnes, selon la façon dont vous l'affichez. à l'esprit, dans le tableau 2D, ce tableau std prend en charge.

Vous pouvez également utiliser la solution de Kevin Loney:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]

mais si vous utilisez le tableau std, le code doit être différent:

array<int, sizeX*sizeY> ary = array<int, sizeX*sizeY>();
ary.at(i*sizeY+j);

Et toujours avoir les fonctions uniques du tableau std.

Notez que vous pouvez toujours accéder aux éléments du tableau std en utilisant les parenthèses [], et vous n'avez pas à appeler la fonction at . Vous pouvez également définir et affecter une nouvelle variable int qui calculera et conservera le nombre total de éléments du tableau std et utilise sa valeur au lieu de répéter sizeX*sizeY

Vous pouvez définir votre propre classe générique de tableau à deux dimensions et définir le constructeur de la classe de tableau à deux dimensions pour qu'il reçoive deux entiers afin de spécifier le nombre de lignes et de colonnes du nouveau tableau à deux dimensions et définir la fonction get qui reçoit deux paramètres d'entier. qui accède à un élément du tableau à deux dimensions et renvoie sa valeur et définit la fonction recevant trois paramètres, les deux premiers étant des entiers spécifiant la ligne et la colonne du tableau à deux dimensions, et le troisième paramètre étant la nouvelle valeur de élément. Son type dépend du type que vous avez choisi dans la classe générique.

Vous pourrez implémenter tout cela en utilisant soit le tableau normal c ++ (pointeurs ou sans) ou le tableau std et en utilisant l’une des idées suggérées par d’autres personnes, et facilitant son utilisation comme le tableau cli, ou similaire au tableau à deux dimensions que vous pouvez définir, attribuer et utiliser en C #.

J'ai utilisé ce système pas élégant mais rapide, facile et fonctionnel. Je ne vois pas pourquoi cela ne fonctionnerait pas car la seule façon pour le système de créer un tableau de grande taille et d'accéder aux pièces est de ne pas le couper en parties

#define DIM 3
#define WORMS 50000 //gusanos

void halla_centros_V000(double CENW[][DIM])
{
    CENW[i][j]=...
    ...
}


int main()
{
    double *CENW_MEM=new double[WORMS*DIM];
    double (*CENW)[DIM];
    CENW=(double (*)[3]) &CENW_MEM[0];
    halla_centros_V000(CENW);
    delete[] CENW_MEM;
}
0
mathengineer

Le but de cette réponse n'est pas d'ajouter quelque chose de nouveau que les autres ne couvrent pas déjà, mais d'étendre la réponse de @Kevin Loney.

Vous pouvez utiliser la déclaration de poids léger:

int *ary = new int[SizeX*SizeY]

et la syntaxe d'accès sera:

ary[i*SizeY+j]     // ary[i][j]

mais cela est lourd pour la plupart des gens et peut prêter à confusion. Vous pouvez donc définir une macro comme suit:

#define ary(i, j)   ary[(i)*SizeY + (j)]

Vous pouvez maintenant accéder au tableau en utilisant la syntaxe très similaire, ary(i, j) // means ary[i][j]..__, ce qui présente les avantages d'être simple et esthétique, et en même temps, l'utilisation d'expressions à la place des index est également plus simple et moins déroutante.

Pour accéder, par exemple, à ary [2 + 5] [3 + 8], vous pouvez écrire ary(2+5, 3+8) à la place de la fonction ary[(2+5)*SizeY + (3+8)], à l'aspect complexe, c’est-à-dire qu’elle enregistre les parenthèses et améliore la lisibilité.

Mises en garde:

  • Bien que la syntaxe soit très similaire, ce n'est PAS la même chose.
  • Si vous passez le tableau à d'autres fonctions, SizeY doit être transmis avec le même nom (ou être déclaré en tant que variable globale).

Ou, si vous devez utiliser le tableau dans plusieurs fonctions, vous pouvez ajouter SizeY également comme autre paramètre dans la définition de la macro, comme ceci:

#define ary(i, j, SizeY)  ary[(i)*(SizeY)+(j)]

Vous avez eu l'idée. Bien sûr, cela devient trop long pour être utile, mais cela peut encore empêcher la confusion entre + et *.

Ce n'est pas recommandé définitivement, et la plupart des utilisateurs expérimentés le qualifieront de mauvaise pratique, mais je ne pouvais pas m'empêcher de le partager à cause de son élégance.

P.S .: J'ai testé cela, et la même syntaxe fonctionne (en tant que lvalue et rvalue) sur les compilateurs g ++ 14 et g ++ 11.

0
Zargles

Je vous ai laissé avec une solution qui fonctionne le mieux pour moi, dans certains cas. Surtout si on connaît [la taille de?] Une dimension du tableau. Très utile pour un tableau de caractères, par exemple si nous avons besoin d'un tableau de taille variable de tableaux de caractères [20].

int  size = 1492;
char (*array)[20];

array = new char[size][20];
...
strcpy(array[5], "hola!");
...
delete [] array;

La clé correspond aux parenthèses dans la déclaration du tableau.

0
FedeBsAs

L'exemple ci-dessous peut aider,

int main(void)
{
    double **a2d = new double*[5]; 
    /* initializing Number of rows, in this case 5 rows) */
    for (int i = 0; i < 5; i++)
    {
        a2d[i] = new double[3]; /* initializing Number of columns, in this case 3 columns */
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            a2d[i][j] = 1; /* Assigning value 1 to all elements */
        }
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << a2d[i][j] << endl;  /* Printing all elements to verify all elements have been correctly assigned or not */
        }
    }

    for (int i = 0; i < 5; i++)
        delete[] a2d[i];

    delete[] a2d;


    return 0;
}
0
The_Learner