Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - [risolto] Passare matrice dinamica a routine in C
Forum - C/C++ - [risolto] Passare matrice dinamica a routine in C

Avatar
Carlo (Member)
Guru


Messaggi: 833
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 17:19
Martedì, 09/02/2021
Ho iniziato a studiare le matrici dinamiche, non ho capito come devo fare per passare ad una stessa routine una matrice dinamica o una matrice statica.
Il seguente codice ha una void che visualizza il contenuto di una matrice con due dimensioni uguali, funziona correttamente con le matrici statiche, ma non se la matrice è stata inizializzata in runtime, pensavo di aver sbagliato l'uso di malloc, ma se stampo la matrice dinamica senza passare per la routine, la matrice sembra allocata e riempita correttamente:
Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define DIM 5
  5.  
  6.  
  7. int **dinamica;
  8. int statica[DIM][DIM];
  9.  
  10. void visualizza(int m[DIM][DIM]){
  11.  
  12.     for (int r=0; r<DIM; r++){
  13.         printf("\n");
  14.         for (int c=0; c<DIM; c++){
  15.             printf("%02d ",m[r][c]);
  16.         }
  17.     }
  18.     printf("\n\n");
  19. }
  20.  
  21. int main()
  22.  
  23. {   // riempio la matrice statica a due dimensioni come fosse un vettore seriale
  24.     printf("Matrice statica a due dimensioni riempita serialmente");
  25.     int *s=*statica; // s punta l'inizio della matrice
  26.     for (int i=0; i<DIM*DIM; i++){
  27.         s[i]=i; // posso riempire serialmente
  28.     }
  29.     visualizza(statica); // funziona
  30.  
  31.     // alloco una matrice dinamica a due dimensioni
  32.     dinamica = (int **) malloc (DIM*sizeof(int *));
  33.     for(int r=0; r<DIM; r++)
  34.         dinamica[r] = (int *) malloc(DIM*sizeof(int));
  35.  
  36.     // riempio la matrice dinamica per riga e colonna
  37.     for (int r=0; r<DIM; r++){
  38.         for (int c=0; c<DIM; c++){
  39.             dinamica[r][c]=c+r*DIM ;
  40.         }
  41.     }
  42.     printf("Matrice dinamica visualizzata errata con routine");
  43.     visualizza(dinamica); // ho un warning puntatore incompatibile! come si deve passare?
  44.  
  45.     printf("Matrice dinamica visualizzata direttamente e correttamente");
  46.     for (int r=0; r<DIM; r++){
  47.         printf("\n");
  48.         for (int c=0; c<DIM; c++){
  49.             printf("%02d ",dinamica[r][c]);
  50.         }
  51.     }
  52.     printf("\n\n");
  53.  
  54.     // dealloco
  55.     for (int r=0; r<DIM; r++)
  56.         free(dinamica[r]);
  57.     free(dinamica);
  58.     return 0;
  59. }


se modifico la dichiarazione della void in:
Codice sorgente - presumibilmente C/C++

  1. void visualizza(int **m)


la routine visualizza(), funziona con la matrice dinamica ma non funziona con la matrice statica...

Ultima modifica effettuata da Carlo il 11/02/2021 alle 13:01


in programmazione tutto è permesso
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 613
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 22:31
Mercoledì, 10/02/2021
Ciao Carlo

Ho cercato e ricercato una soluzione al tuo quesito, trovando diverse pagine che mi davano soluzioni sicuramente corrette (alcune facevano capo a siti universitari) ma che non son riuscito a sentire vicine al mio modo di intendere le cose. Così ho provato a cercare una via d'uscita tutta mia -- come al solito ti metto in guardia, ricordandoti che non sono un esperto e che potrei prendere cantonate di tutto rispetto. Detto questo, ecco cosa ho pensato...

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void visualizza(void *m, size_t qr, size_t qc) {
  5.     int r, c, *mi = m;
  6.  
  7.     for( r=0; r<qr; r++ )
  8.         for( c=0; c<qc; c++ )
  9.             printf( "%02d%c", mi[r*qr+c], c!=qc-1?' ':'\n' );
  10. }
  11.  
  12. int **crea_matrice( size_t qr, size_t qc ) {
  13.     int **m = NULL;
  14.  
  15.     if( 0!=qr && 0!=qc ) { // deve poter contenere qualcosa!
  16.         m = calloc( qr*sizeof(*m) + qr*qc*sizeof(**m), 1 ); // un unico blocco
  17.  
  18.         if( NULL != m ) {
  19.             size_t r;
  20.  
  21.             for( r=0; r<qr; ++r )
  22.                 m[r] = (int*)((m+qr)+r*qc); // colloca i puntatori alle righe
  23.                                             // in testa al blocco allocato in m
  24.         }
  25.     }
  26.  
  27.     return m;
  28. }
  29.  
  30. int main() {
  31.     const int qr = 5; // qr: quantita' righe
  32.     const int qc = 5; // qc; quantita' colonne
  33.     int statica[qr][qc];
  34.     int **dinamica = NULL;
  35.     int i, r, c, *s;
  36.  
  37.     // riempio la matrice statica a due dimensioni come fosse un vettore seriale
  38.     printf("Matrice statica\nriempita serialmente\n");
  39.     s = *statica; // s punta l'inizio della matrice
  40.     for( i=0; i<qr*qc; i++ ) s[i]=i; // posso riempire serialmente
  41.     visualizza( statica, qr, qc ); // funziona
  42.  
  43.     // alloco una matrice dinamica a due dimensioni
  44.     dinamica = crea_matrice( qr, qc );
  45.     if( !dinamica ) { puts( "Allocazione fallita.\n" ); return 0; }
  46.     // posso riempire serialmente anche la matrice dinamica; con +qr passi
  47.     // oltre alla zona riservata ai puntatori, fino a quella riservata ai dati
  48.     for( s=(int*)(dinamica+qr), i=0; i<qr*qc; i++ ) s[i]=i;
  49.     printf("\nMatrice dinamica\nvisualizzata con routine\n");
  50.     visualizza( dinamica+qr, qr, qc ); // con +qr passi oltre alla zona
  51.                 // riservata ai puntatori, fino a quella riservata ai dati
  52.  
  53.     printf( "\nMatrice dinamica\nvisualizzata direttamente\n" );
  54.     for( r=0; r<qr; r++ )
  55.         for ( c=0; c<qc; c++ )
  56.             printf( "%02d%c", dinamica[r][c], c!=qc-1?' ':'\n' );
  57.  
  58.     free( dinamica ); // dealloco; avendo allocato un unico blocco, la
  59.                       // deallocazione si risolve in un'unica chiamata
  60.     return 0;
  61. }



Noterai che ho usato un metodo di allocazione della matrice dinamica diverso da quello che hai usato tu. Col mio metodo ( lo trovi "isolato" in crea_matrice() ) finisci per avere un unico blocco allocato, con tutti i puntatori "in testa", seguiti dai dati in posizioni contigue.

A quel punto, per far "digerire" al compilatore C (non C++!) il passaggio di puntatori diversi, ho usato un generico void*, che viene convertito in int** all'interno di visualizza(). L'idea è passare alla funzione l'indirizzo al primo elemento del blocco di memoria dove si trovano, in posizioni contigue, tutti i dati. Per far questo, quando tratto la matrice dichiarata come int statica[qr][qc] passo statica e basta, mentre quando tratto la matrice allocata con crea_matrice() passo statica+qr per "passare oltre" allo spazio riservato ai puntatori in testa al blocco.

Lo so che è una forzatura, prendila per quel che vale.

Ultima modifica effettuata da AldoBaldo il 10/02/2021 alle 23:03


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 833
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 12:54
Giovedì, 11/02/2021
Bingo!!
Con il tuo esempio e altre ricerche, ho capito che la mia dichiarazione di matrice dinamica, è una collezione di doppi puntatori che non necessariamente puntano a zone contigue di memoria.
Infatti tu hai allocato un unico blocco, ho variato un po', ora la matrice dinamica si comporta come la matrice statica:
Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define DIMr 5
  5. #define DIMc 10
  6.  
  7. void visualizza(int m[DIMr][DIMc]){
  8.     for (int r=0; r<DIMr; r++){
  9.         printf("\n");
  10.         for (int c=0; c<DIMc; c++) printf("%02d ", m[r][c]);
  11.     }
  12.     printf("\n\n");
  13. }
  14.  
  15. int main(){
  16.     int **dinamica=NULL, *ps=NULL, *pd=NULL, i;
  17.     int statica[DIMr][DIMc];
  18.  
  19.     printf("statica 2dim riempita serialmente e visualizzata con routine a indici\n");
  20.     ps=*statica; // ps punta l'inizio della matrice
  21.     for (i=0; i<DIMr*DIMc; i++) ps[i]=i+1; // posso riempire serialmente, tabellina dell'1
  22.     visualizza(statica); // funziona
  23.  
  24.     // alloco una matrice dinamica a due dimensioni con righe contigue
  25.     dinamica=(int **) malloc(DIMr*sizeof(int *));
  26.     dinamica[0]=(int*) malloc(DIMr*DIMc*sizeof(int));
  27.     for (i=1; i<DIMr; i++) dinamica[i]=dinamica[0]+i*DIMc;
  28.  
  29.     printf("dinamica 2dim riempita serialmente e visualizzata con routine a indici\n");
  30.     pd=*dinamica; // pd punta l'inizio della matrice
  31.     for (i=0; i<DIMr*DIMc; i++) pd[i]=(i+1)*2; // posso riempire serialmente, tabellina del 2
  32.     visualizza(pd); // funziona
  33.  
  34.     free(dinamica[0]);
  35.     free(dinamica);
  36.     return 0;
  37. }


Ho cercato di trovare una forma più logica per me, perché così sono in grado di ricordarla.
Il tuo codice mi ha dato delle dritte e delle conferme, ma ha aperto ulteriori dubbi, l'ho archiviato tra gli esempi da studiare.:k:
Sai dove applicherò tali nuove conoscenze! :heehee:

Ultima modifica effettuata da Carlo il 27/02/2021 alle 0:09


in programmazione tutto è permesso
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 613
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 15:35
Giovedì, 11/02/2021
Fantastico!
Tante teste, tante idee. :)


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote