66 votes

Comment travailler avec des tableaux multidimensionnels dynamiques en C?

Est-ce que quelqu'un sait comment puis-je utiliser des tableaux multi-dimensionnels à l'aide de C? Est-ce possible?

Merci beaucoup...

98voto

Jens Gustedt Points 40410

Depuis C99, 13 ans maintenant, C a 2D tableaux avec des dynamiques de limites. Si vous voulez éviter qu'une telle bête sont allouées sur la pile (qui doit), vous pouvez attribuer facilement d'un seul coup comme suit

double (*A)[n] = malloc(sizeof(double[n][n]));

et c'est tout. Vous pouvez facilement l'utiliser comme vous sont utilisés pour la 2D tableaux avec quelque chose comme A[i][j]. Et n'oubliez pas qu'un à la fin

free(A);

Randy Meyers a écrit une série d'articles expliquant à longueur variable tableaux (Blaise).

82voto

schnaader Points 26212

Avec l'allocation dynamique, à l'aide de malloc:

int** x;

x = (int**)malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = (int*)malloc(dimension2_max * sizeof(int));
}

[...]

for (int i = 0; i < dimension1_max; i++) {
  free(x[i]);
}
free(x);

Il alloue un tableau 2D de taille dimension1_max * dimension2_max. Ainsi, par exemple, si vous voulez un 640*480 array (f.e. les pixels d'une image), utilisez dimension1_max = 640, dimension2_max = 480. Vous pouvez ensuite accéder au tableau à l'aide d' x[d1][d2]d1 = 0..639, d2 = 0..479.

Mais une recherche sur ou google révèle également d'autres possibilités, par exemple dans cette SORTE de question

Notez que votre tableau ne sera pas affecter une région contiguë de la mémoire (640*480 octets) dans ce cas, qui pourrait donner des problèmes avec les fonctions qu'assument cette. Donc, pour obtenir la matrice de satisfaire à la condition, remplacer le malloc bloc ci-dessus avec ceci:

int** x;
int* temp;

x = (int**)malloc(dimension1_max * sizeof(int*));
temp = (int*)malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = temp + (i * dimension2_max);
}

53voto

dmckee Points 50318

Notions de base

Les tableaux en c sont déclarées et accessible à l'aide de l' [] de l'opérateur. De sorte que

int ary1[5];

déclare un tableau de 5 entiers. Les éléments sont numérotés à partir de zéro, de sorte ary1[0] est le premier élément, et ary1[4] est le dernier élément. Note1: Il n'y a pas d'initialisation par défaut, de sorte que la mémoire occupée par le tableau peut initialement contenir quelque chose. Note2: ary1[5] accède à la mémoire dans un état indéfini (qui peuvent même ne pas être accessibles pour vous), afin de ne pas le faire!

Multi-dimensions des tableaux sont mis en œuvre comme un tableau de tableaux (de tableaux (de ... ) ). Donc

float ary2[3][5];

déclare un tableau de 3 tableaux unidimensionnels de 5 nombres à virgule flottante chaque. Maintenant, ary2[0][0] est le premier élément du premier tableau, ary2[0][4] est le dernier élément de la première pile, et ary2[2][4] est le dernier élément de la dernière rangée. Le '89 norme exige que ces données soient contigus (sec. A8.6.2 sur la page 216 de mon K&R 2e. ed.) mais semble être agnostique sur le rembourrage.

En essayant d'aller de dynamique en plus d'une dimension

Si vous ne connaissez pas la taille du tableau au moment de la compilation, vous aurez envie d'allouer dynamiquement de la matrice. Il est tentant d'essayer

double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */

qui devrait fonctionner si le compilateur n'est pas pavé que de l'allocation (bâton de l'espace supplémentaire entre les tableaux unidimensionnels). Il pourrait être plus sûr de aller avec:

double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */

mais de toute façon, l'astuce consiste à déréférencement du temps. Vous ne pouvez pas écrire buf[i][j] car buf a le mauvais type. Et vous ne pouvez pas utiliser

double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */

parce que le compilateur s'attend hdl4 être l'adresse d'une adresse d'un double. De même, vous pouvez utiliser double incomplete_ary4[][]; parce que c'est une erreur;

Alors, que pouvez-vous faire?

  • Faire la ligne et de la colonne de l'arithmétique de vous-même
  • Répartir dans une fonction
  • Utiliser un tableau de pointeurs (le mécanisme qrdl parle)

Faites le calcul vous-même

Simplement calculer l'offset de mémoire pour chaque élément comme ceci:

  for (i=0; i<3; ++i){
     for(j=0; j<3; ++j){
        buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                             padding in this case */
     }
  }

Répartir dans une fonction

Définir une fonction qui prend la taille nécessaire comme argument et procéder comme normal

void dary(int x, int y){
  double ary4[x][y];
  ary4[2][3] = 5;
}

Un tableau de pointeurs

Réfléchissez à ceci:

double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
   hdl5[i] = malloc(5*sizeof(double))
   /* Error checking */
}

Maintenant, hdl5 de points à un tableau de pointeurs, chacun de qui pointe vers un tableau de double. Le bit est cool c'est que vous pouvez utiliser le tableau à deux dimensions de notation pour accéder à cette structure---hdl5[0][2] obtient au moyen de l'élément de la première ligne---mais c'est néanmoins un autre type d'objet que d'un tableau à deux dimensions déclarées par double ary[3][5];.

Cette structure est plus souple alors un tableau à deux dimensions (parce que les lignes n'ont pas besoin d'être de la même longueur), mais l'accès sera généralement plus lent et nécessite plus de mémoire (vous avez besoin d'un endroit pour tenir l'intermédiaire de pointeurs).

Notez que puisque je n'ai pas tout de configuration des gardes que vous aurez à garder une trace de la taille de toutes les matrices de vous-même.

L'arithmétique

c fournit pas de support pour le vecteur, une matrice ou un tenseur mathématiques, vous aurez à mettre en œuvre vous-même, ou de les amener dans une bibliothèque.

La Multiplication par un scaler et de l'addition et de la soustraction de matrices de même rang sont facile: il suffit de boucler sur les éléments et effectuer l'opération que vous allez. Intérieure produits sont de même simple.

Extérieur de produits signifie plus de boucles.

14voto

John Bode Points 33046

Si vous connaissez le nombre de colonnes au moment de la compilation, c'est assez simple:

#define COLS ...
...
size_t rows;
// get number of rows
T (*ap)[COLS] = malloc(sizeof *ap * rows); // ap is a *pointer to an array* of T

Vous pouvez traiter l' ap comme n'importe quel tableau 2D:

ap[i][j] = x;

Quand vous avez fini vous le désallouer comme

free(ap);

Si vous ne savez pas le nombre de colonnes au moment de la compilation, mais vous travaillez avec un compilateur C99 ou un C2011 compilateur qui prend en charge de longueur variable des tableaux, c'est encore assez simple:

size_t rows;
size_t cols;
// get rows and cols
T (*ap)[cols] = malloc(sizeof *ap * rows);
...
ap[i][j] = x;
...
free(ap);

Si vous ne savez pas le nombre de colonnes au moment de la compilation et vous travaillez avec une version de C qui ne supportent pas de longueur variable des tableaux, alors vous aurez besoin de faire quelque chose de différent. Si vous avez besoin de tous les éléments pour être affectés dans un espace contigu (comme un tableau), alors vous pouvez allouer de la mémoire comme un tableau 1D, et de calculer un 1D offset:

size_t rows, cols;
// get rows and columns
T *ap = malloc(sizeof *ap * rows * cols);
...
ap[i * rows + j] = x;
...
free(ap);

Si vous n'avez pas besoin de la mémoire pour être contiguë, vous pouvez suivre les deux étapes de la méthode de répartition:

size_t rows, cols;
// get rows and cols
T **ap = malloc(sizeof *ap * rows);
if (ap)
{
  size_t i = 0;
  for (i = 0; i < cols; i++)
  {
    ap[i] = malloc(sizeof *ap[i] * cols);
  }
}

ap[i][j] = x;

Depuis que l'allocation a été un processus en deux étapes, de libération de la mémoire doit aussi être un processus en deux étapes:

for (i = 0; i < cols; i++)
  free(ap[i]);
free(ap);

-1voto

Rahul Tripathi Points 1

Malloc fera l'affaire.

  int rows = 20;
 int cols = 20;
 int *array;

  array = malloc(rows * cols * sizeof(int));
 

Reportez-vous à l'article ci-dessous pour obtenir de l'aide: -

http://courses.cs.vt.edu/~cs2704/spring00/mcquain/Notes/4up/Managing2DArrays.pdf

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X