Moyen correct de passer un tableau à deux dimensions dans une fonction

J’ai un tableau à deux dimensions et je le transmets à une fonction pour effectuer certaines opérations. J’aimerais connaître la bonne façon de le faire …

#define numRows 3 #define numCols 7 #define TotalNum (numRows*numCols) int arr[numRows][numCols] = {{0,1,2,3,4,5,6}, {7,8,9,10,11,12,13},{14,15,16,17,18,19,20}}; void display(int **p) { printf("\n"); for (int i = 0; i< numRows;i++) { for ( int j = 0;j< numCols;j++) { printf("%i\t",p[i][j]); } printf("\n"); } } int main() { display(arr); } 

Je reçois un message d’erreur:

 'display': cannot convert parameter1 from 'int' to 'int*' 

Est-ce la bonne façon de faire passer un tableau à deux dimensions dans une fonction? Si non, quelle est la bonne façon?

Vous devriez déclarer votre fonction comme ceci:

 void display(int p[][numCols]) 

Cette FAQ C explique pourquoi. L’essentiel est que les tableaux se transforment en pointeurs une fois , cela ne se produit pas récursivement. Un tableau de tableaux se désintègre en un pointeur vers un tableau, et non en un pointeur vers un pointeur.

Si (comme dans votre cas), vous connaissez les dimensions du tableau au moment de la compilation, vous pouvez écrire juste un void display(int p[][numCols]) .

Quelques explications: Vous savez probablement que lorsque vous passez un tableau à une fonction, vous transmettez réellement un pointeur au premier membre. En langage C, le tableau 2D n’est qu’un tableau de tableaux. Pour cette raison, vous devez passer la fonction un pointeur sur le premier sous-tableau du tableau 2D. Donc, la manière naturelle est de dire int (*p)[numCols] (cela signifie que p est un pointeur, un tableau de numCols ints ). Dans la déclaration de fonction, vous avez le “raccourci” p[] , ce qui signifie exactement la même chose que (*p) (mais indique au lecteur, que vous passez un pointeur sur un début de tableau et non sur une seule variable)

Vous faites mal. Vous pouvez passer un tableau à deux dimensions à l’aide d’un pointeur vers un tableau, ou simplement passer un tableau ou un pointeur unique.

 #define numRows 3 #define numCols 7 void display(int (*p)[numcols],int numRows,int numCols)//First method// void display(int *p,int numRows,int numCols) //Second Method// void display(int numRows,int numCols,int p[][numCols]) //Third Method { printf("\n"); for (int i = 0; i < numRows;i++) { for ( int j = 0; j < numCols;j++) { printf("%i\t",p[i][j]); } printf("\n"); } } int main() { display(arr,numRows,numCols); } 

Il existe plusieurs façons, parfois équivalentes, de le faire. En déclarant un tableau (cf. method_c() ), en utilisant un pointeur (cf. method_b() ) ou en utilisant un pointeur sur un tableau d’un tableau (cf. method_a() ). method_b() , en utilisant un seul pointeur, est un peu plus difficile à obtenir, car il n’est pas facile d’utiliser l’indexation de tableau standard et, par conséquent, nous utilisons l’arithmétique de pointeur. method_a() et method_c() sont fondamentalement équivalentes car les tableaux se désintègrent de manière non récursive en pointeurs lors de la compilation. Voici un petit programme illustrant les trois méthodes. Nous initialisons d’abord un arret 2x4 ar dans une simple boucle pour l’imprimer. Il ressemblera à ceci:

 arr: 0 1 2 3 0 1 2 3 

Ensuite, nous appelons les trois méthodes. method_a() ajoute 1, method_b() ajoute 2 et method_c() ajoute 3 à tous les éléments. Après chaque appel, nous imprimons à nouveau le tableau. Si une fonction fonctionne correctement, vous la verrez facilement sur la sortie. La taille est arbitraire et peut être régulée via les deux macros ROW et COL . Une dernière remarque, method_c() repose sur un tableau de longueur variable présent depuis C99 .

 #include  #include  #define ROW 2 #define COL 4 void method_a(int m, int n, int (*ptr_arr)[n]); void method_b(int m, int n, int *ptr_arr); void method_c(int m, int n, int arr[][n]); int main(int argc, char *argv[]) { int arr[ROW][COL]; int i; int j; for(i = 0; i < ROW; i++) { for(j = 0; j < COL; j++) { arr[i][j] = j; } } printf("Original array:\n"); for (i = 0; i < ROW; i++) { for(j = 0; j < COL; j++) { printf("%d\t", arr[i][j]); } printf("\n"); } printf("\n\n"); method_a(ROW, COL, arr); printf("method_a() array:\n"); for (i = 0; i < ROW; i++) { for(j = 0; j < COL; j++) { printf("%d\t", arr[i][j]); } printf("\n"); } printf("\n\n"); printf("method_b() array:\n"); method_b(ROW, COL, (int *)arr); for (i = 0; i < ROW; i++) { for(j = 0; j < COL; j++) { printf("%d\t", arr[i][j]); } printf("\n"); } printf("\n\n"); method_c(ROW, COL, arr); printf("method_c() array:\n"); for (i = 0; i < ROW; i++) { for(j = 0; j < COL; j++) { printf("%d\t", arr[i][j]); } printf("\n"); } printf("\n\n"); return EXIT_SUCCESS; } void method_a(int m, int n, int (*ptr_arr)[n]) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { ptr_arr[i][j] = j + 1; } } } void method_b(int m, int n, int *ptr_arr) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { /* We need to use pointer arithmetic when indexing. */ *((ptr_arr + i * n) + j) = j + 2; } } /* The whole function could have also been defined a bit different by taking * the i index out of the pointer arithmetic. n alone will then provide our * correct offset to the right. This may be a bit easier to understand. Our * for-loop would then look like this: * for (i = 0; i < m; i++) * { * for (j = 0; j < n; j++) * { * *((ptr_arr + n) + j) = j + 2; * } * ptr_arr++; * }*/ } void method_c(int m, int n, int arr[][n]) { int i, j; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { arr[i][j] = j + 3; } } } 

Déclarez-le simplement

 void display(int (*p)[numCols][numRows]); 

De cette façon, votre pointeur p achemine toutes les informations nécessaires et vous pouvez en extraire toutes les dimensions sans répéter les numRows et les numRows .

 void display(int (*p)[numCols][numRows]) { size_t i, j; printf("sizeof array=%zu\n", sizeof *p); printf("sizeof array[]=%zu\n", sizeof **p); printf("sizeof array[][]=%zu\n", sizeof ***p); size_t dim_y = sizeof *p / sizeof **p; printf("dim_y = %zu\n", dim_y); size_t dim_x = sizeof **p / sizeof ***p; printf("dim_x = %zu\n", dim_x); for(i=0; i 

Ceci est particulièrement intéressant si vous utilisez des typedefs (que je n'aime pas btw)

  typedef int masortingx[5][6]; 

Dans ce cas, les dimensions ne sont pas visibles dans la signature de la fonction mais la fonction aura toujours les valeurs correctes pour les dimensions.

Vous pouvez modifier la signature de la méthode d’affichage comme suit:

 void display(int (*p)[numCols]) 

Ici, p est un pointeur sur la ligne d’un tableau 2D. Le pointeur n’a besoin que de connaître le nombre de colonnes du tableau.

En fait, le pointeur doit connaître la taille de chaque ligne. Ceci est très important pour l’arithmétique du pointeur. Ainsi, lorsque vous incrémentez le pointeur, le pointeur doit pointer vers la ligne suivante.

Notez que p n’est pas un pointeur entier normal. C’est un pointeur entier à la taille de la mémoire égal à integer_size x columns .

En général, vous n’avez rien à changer. display(arr) est très bien.