Modo corretto per far passare una matrice bidimensionale in una funzione

Ho un array bidimensionale e lo sto passando in una funzione per eseguire determinate operazioni. Mi piacerebbe sapere il modo corretto di farlo …

#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); } 

Ottengo un messaggio di errore:

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

È questo il modo corretto di far passare una matrice bidimensionale in una funzione? In caso contrario, qual è il modo corretto?

Dovresti dichiarare la tua funzione in questo modo:

 void display(int p[][numCols]) 

Questa FAQ di C spiega completamente perché. L’essenza di ciò è che gli array si decompongono in puntatori una volta , non accade in modo ricorsivo. Un array di array decade in un puntatore a un array, non in un puntatore a un puntatore.

Se (come nel tuo caso), conosci le dimensioni dell’array in fase di compilazione, puoi scrivere solo void display(int p[][numCols]) .

Qualche spiegazione: probabilmente sai che quando si passa un array a una funzione, si passa effettivamente un puntatore al primo membro. Nel linguaggio C, l’array 2D è solo una matrice di matrici. Per questo motivo, è necessario passare la funzione un puntatore al primo sub-array dell’array 2D. Quindi, il modo naturale, è int (*p)[numCols] (che significa p è un puntatore, a una matrice di numCols interi ). Nella dichiarazione di funzione, si ha la “scorciatoia” p[] , che significa esattamente la stessa cosa come (*p) (ma dice al lettore, che si passa un puntatore a un inizio di matrice, e non a una sola variabile)

Stai facendo nel modo sbagliato. È ansible passare array 2-d con l’aiuto del puntatore a un array, o semplicemente passare un array o attraverso il puntatore Single.

 #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); } 

Ci sono diversi modi, a volte equivalenti, per farlo. Dichiarando una matrice (cf method_c() ), usando un puntatore (cf method_b() ) o usando un puntatore a una matrice di una matrice (cfr method_a() ). method_b() , utilizzando un singolo puntatore, è leggermente più difficile da ottenere poiché non è facile usare l’indicizzazione di array standard e, quindi, usiamo l’aritmetica del puntatore. method_a() e method_c() sono fondamentalmente equivalenti poiché gli array decadono non ricorsivamente ai puntatori durante la compilazione. Ecco un piccolo programma che illustra tutti e tre i metodi. Inizialmente inizializziamo un arr array 2x4 in un semplice ciclo for e lo stampiamo. Sembrerà così:

 arr: 0 1 2 3 0 1 2 3 

Successivamente chiamiamo tutti e tre i metodi. method_a() aggiunge 1, method_b() aggiunge 2 e method_c() aggiunge 3 a tutti gli elementi. Dopo ogni chiamata stampiamo nuovamente l’array arr . Se una funzione ha funzionato correttamente lo vedrai facilmente sull’output. La dimensione è arbitraria e può essere regolata tramite i due macro ROW e COL . Un’ultima nota, method_c() si basa sulla matrice a lunghezza variabile presente da 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; } } } 

Lo dichiari semplicemente

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

In questo modo il tuo puntatore p trasmette tutte le informazioni necessarie ed è ansible estrarre tutte le dimensioni da esso senza ripetere numCols e numRows ripetutamente.

 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 

Questo è particolarmente interessante se usi typedef (che non mi piace btw)

  typedef int matrix[5][6]; 

In tal caso le dimensioni non sono visibili nella firma della funzione, ma la funzione avrà comunque i valori corretti per le dimensioni.

È ansible modificare la firma del metodo di visualizzazione come segue:

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

Qui p è un puntatore alla riga di un array 2D. Il puntatore deve solo conoscere il numero di colonne nell’array.

In realtà, il puntatore deve conoscere la dimensione di ogni riga. Questo è molto importante per l’aritmetica del puntatore. In modo che quando si incrementa il puntatore, il puntatore deve puntare alla riga successiva.

Nota qui, p non è un normale puntatore intero. È un puntatore intero alla dimensione della memoria uguale a integer_size x columns .

In main non è necessario modificare nulla. display(arr) va bene.