Est-ce que quelqu'un sait comment utiliser des tableaux multidimensionnels alloués dynamiquement à l'aide de C? Est-ce possible?
Avec allocation dynamique, en utilisant malloc:
int** x;
x = malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
x[i] = malloc(dimension2_max * sizeof(int));
}
[...]
for (int i = 0; i < dimension1_max; i++) {
free(x[i]);
}
free(x);
Cela alloue un tableau 2D de taille dimension1_max
* dimension2_max
. Ainsi, par exemple, si vous souhaitez un tableau 640 * 480 (par exemple, une image), utilisez dimension1_max
= 640, dimension2_max
= 480. Vous pouvez ensuite accéder au tableau à l'aide de x[d1][d2]
où d1
= 0..639, d2
= 0. .479.
Mais une recherche sur SO ou Google révèle également d'autres possibilités, par exemple dans cette question SO
Notez que votre tableau n'allouera pas de région de mémoire contiguë (640 * 480 octets), ce qui pourrait poser des problèmes avec les fonctions qui le supposent. Donc, pour que le tableau satisfasse à la condition, remplacez le bloc malloc ci-dessus par ceci:
int** x;
int* temp;
x = malloc(dimension1_max * sizeof(int*));
temp = malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
x[i] = temp + (i * dimension2_max);
}
[...]
free(temp);
free(x);
Depuis C99, 13 ans maintenant, C dispose de tableaux 2D à bornes dynamiques. Si vous voulez éviter que de telles bêtes soient allouées sur la pile (ce que vous devriez), vous pouvez les allouer facilement en une fois, comme suit
double (*A)[n] = malloc(sizeof(double[n][n]));
et c'est tout. Vous pouvez ensuite l'utiliser facilement, comme vous êtes utilisé pour des tableaux 2D avec quelque chose comme A[i][j]
. Et n'oubliez pas celui-là à la fin
free(A);
Randy Meyers a écrit une série d'articles expliquant des tableaux de longueur variable (VLA) .
Les tableaux de c sont déclarés et accessibles à l’aide de l’opérateur []
. Pour que
int ary1[5];
déclare un tableau de 5 entiers. Les éléments étant numérotés à partir de zéro, ary1[0]
est le premier élément et ary1[4]
le dernier. Note1: Il n'y a pas d'initialisation par défaut, donc la mémoire occupée par le tableau peut contenir initialement rien . Note2: ary1[5]
accède à la mémoire dans un état non défini (qui peut même ne pas vous être accessible), alors ne le faites pas!
Les tableaux multidimensionnels sont implémentés comme un tableau de tableaux (de tableaux (de ...)). Alors
float ary2[3][5];
déclare un tableau de 3 tableaux unidimensionnels de 5 nombres en virgule flottante chacun. Maintenant, ary2[0][0]
est le premier élément du premier tableau, ary2[0][4]
est le dernier élément du premier tableau et ary2[2][4]
est le dernier élément du dernier tableau. La norme '89 exige que ces données soient contiguës (sec. A8.6.2 à la page 216 de mon K & R 2e éd.) Mais semble être agnostique en ce qui concerne le remplissage.
Si vous ne connaissez pas la taille du tableau au moment de la compilation, vous souhaiterez allouer le tableau de manière dynamique. Il est tentant d'essayer
double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */
ce qui devrait fonctionner si le compilateur ne compresse pas l'allocation (collez un espace supplémentaire entre les tableaux unidimensionnels). Il pourrait être plus sûr d'aller avec:
double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */
mais de toute façon, le truc vient au moment du déréférencement. Vous ne pouvez pas écrire buf[i][j]
car buf
a un type incorrect. Tu ne peux pas non plus utiliser
double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */
parce que le compilateur s'attend à ce que hdl4
soit l'adresse d'une adresse de double. Vous ne pouvez pas non plus utiliser double incomplete_ary4[][];
car il s'agit d'une erreur;
Alors que peux-tu faire?
Il suffit de calculer le décalage 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 */
}
}
Définir une fonction qui prend la taille nécessaire en argument et procéder normalement
void dary(int x, int y){
double ary4[x][y];
ary4[2][3] = 5;
}
Bien entendu, dans ce cas, ary4
est une variable locale et vous ne pouvez pas la renvoyer: tout le travail avec le tableau doit être effectué dans la fonction que vous appelez dans les fonctions que it appelle.
Considère 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
pointe vers un tableau de pointeurs, chacun d’eux pointant vers un tableau de doubles. Le bit cool est que vous pouvez utiliser la notation de tableau à deux dimensions pour accéder à cette structure ---hdl5[0][2]
obtient l’élément central de la première ligne --- mais il s’agit néanmoins d’un type d’objet différent tableau dimensionnel déclaré par double ary[3][5];
.
Cette structure est plus flexible qu'un tableau à deux dimensions (car les lignes ne doivent pas nécessairement avoir la même longueur), mais son accès sera généralement plus lent et nécessite plus de mémoire (vous avez besoin d'un emplacement pour contenir les pointeurs intermédiaires).
Notez que puisque je n’ai pas configuré de gardes, vous devrez vous-même connaître la taille de tous les tableaux.
c ne fournit aucun support pour le calcul vectoriel, matriciel ou tensoriel, vous devrez le mettre en œuvre vous-même ou importer une bibliothèque.
Il est facile de multiplier par un détartreur et d'additionner et de soustraire des tableaux du même rang: il suffit de passer en boucle sur les éléments et d'exécuter l'opération au fur et à mesure. Les produits intérieurs sont pareillement simples.
Les produits extérieurs signifient plus de boucles.
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 ap
comme n'importe quel tableau 2D:
ap[i][j] = x;
Lorsque vous avez terminé, vous le désallouez comme
free(ap);
Si vous ne connaissez pas le nombre de colonnes au moment de la compilation, mais que vous travaillez avec un compilateur C99 ou un compilateur C2011 qui prend en charge les tableaux de longueur variable, la procédure est 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 connaissez pas le nombre de colonnes au moment de la compilation et que vous utilisez une version de C qui ne prend pas en charge les tableaux de longueur variable, vous devrez procéder de manière différente. Si vous avez besoin que tous les éléments soient alloués dans un bloc contigu (comme un tableau standard), vous pouvez alors allouer la mémoire sous forme de tableau 1D et calculer un offset 1D:
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 que la mémoire soit contiguë, vous pouvez suivre une méthode d'allocation en deux étapes:
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;
L'attribution étant un processus en deux étapes, la désallocation doit également être un processus en deux étapes:
for (i = 0; i < cols; i++)
free(ap[i]);
free(ap);
Voici un code de travail qui définit un sous-programme make_3d_array
pour allouer un tableau 3D multidimensionnel avec des éléments N1
, N2
et N3
dans chaque dimension, puis le remplir avec des nombres aléatoires. Vous pouvez utiliser la notation A[i][j][k]
pour accéder à ses éléments.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Method to allocate a 2D array of floats
float*** make_3d_array(int nx, int ny, int nz) {
float*** arr;
int i,j;
arr = (float ***) malloc(nx*sizeof(float**));
for (i = 0; i < nx; i++) {
arr[i] = (float **) malloc(ny*sizeof(float*));
for(j = 0; j < ny; j++) {
arr[i][j] = (float *) malloc(nz * sizeof(float));
}
}
return arr;
}
int main(int argc, char *argv[])
{
int i, j, k;
size_t N1=10,N2=20,N3=5;
// allocates 3D array
float ***ran = make_3d_array(N1, N2, N3);
// initialize pseudo-random number generator
srand(time(NULL));
// populates the array with random numbers
for (i = 0; i < N1; i++){
for (j=0; j<N2; j++) {
for (k=0; k<N3; k++) {
ran[i][j][k] = ((float)Rand()/(float)(Rand_MAX));
}
}
}
// prints values
for (i=0; i<N1; i++) {
for (j=0; j<N2; j++) {
for (k=0; k<N3; k++) {
printf("A[%d][%d][%d] = %f \n", i,j,k,ran[i][j][k]);
}
}
}
free(ran);
}
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