Oppure

Loading
09/02 16:19
Carlo
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:
#include <stdio.h>
#include <stdlib.h>

#define DIM 5


int **dinamica;
int statica[DIM][DIM];

void visualizza(int m[DIM][DIM]){

    for (int r=0; r<DIM; r++){
        printf("\n");
        for (int c=0; c<DIM; c++){
            printf("%02d ",m[r][c]);
        }
    }
    printf("\n\n");
}

int main()

{   // riempio la matrice statica a due dimensioni come fosse un vettore seriale
    printf("Matrice statica a due dimensioni riempita serialmente");
    int *s=*statica; // s punta l'inizio della matrice
    for (int i=0; i<DIM*DIM; i++){
        s[i]=i; // posso riempire serialmente
    }
    visualizza(statica); // funziona

    // alloco una matrice dinamica a due dimensioni
    dinamica = (int **) malloc (DIM*sizeof(int *));
    for(int r=0; r<DIM; r++)
        dinamica[r] = (int *) malloc(DIM*sizeof(int));

    // riempio la matrice dinamica per riga e colonna
    for (int r=0; r<DIM; r++){
        for (int c=0; c<DIM; c++){
            dinamica[r][c]=c+r*DIM ;
        }
    }
    printf("Matrice dinamica visualizzata errata con routine");
    visualizza(dinamica); // ho un warning puntatore incompatibile! come si deve passare?

    printf("Matrice dinamica visualizzata direttamente e correttamente");
    for (int r=0; r<DIM; r++){
        printf("\n");
        for (int c=0; c<DIM; c++){
            printf("%02d ",dinamica[r][c]);
        }
    }
    printf("\n\n");

    // dealloco
    for (int r=0; r<DIM; r++)
        free(dinamica[r]);
    free(dinamica);
    return 0;
}

se modifico la dichiarazione della void in:
void visualizza(int **m)

la routine visualizza(), funziona con la matrice dinamica ma non funziona con la matrice statica...
Ultima modifica effettuata da Carlo 11/02 12:01
in programmazione tutto è permesso
10/02 21:31
AldoBaldo
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...

#include <stdio.h>
#include <stdlib.h>

void visualizza(void *m, size_t qr, size_t qc) {
    int r, c, *mi = m;

    for( r=0; r<qr; r++ )
        for( c=0; c<qc; c++ )
            printf( "%02d%c", mi[r*qr+c], c!=qc-1?' ':'\n' );
}

int **crea_matrice( size_t qr, size_t qc ) {
    int **m = NULL;

    if( 0!=qr && 0!=qc ) { // deve poter contenere qualcosa!
        m = calloc( qr*sizeof(*m) + qr*qc*sizeof(**m), 1 ); // un unico blocco

        if( NULL != m ) {
            size_t r;

            for( r=0; r<qr; ++r )
                m[r] = (int*)((m+qr)+r*qc); // colloca i puntatori alle righe
                                            // in testa al blocco allocato in m
        }
    }

    return m;
}

int main() {
    const int qr = 5; // qr: quantita' righe
    const int qc = 5; // qc; quantita' colonne
    int statica[qr][qc];
    int **dinamica = NULL;
    int i, r, c, *s;

    // riempio la matrice statica a due dimensioni come fosse un vettore seriale
    printf("Matrice statica\nriempita serialmente\n");
    s = *statica; // s punta l'inizio della matrice
    for( i=0; i<qr*qc; i++ ) s[i]=i; // posso riempire serialmente
    visualizza( statica, qr, qc ); // funziona

    // alloco una matrice dinamica a due dimensioni
    dinamica = crea_matrice( qr, qc );
    if( !dinamica ) { puts( "Allocazione fallita.\n" ); return 0; }
    // posso riempire serialmente anche la matrice dinamica; con +qr passi
    // oltre alla zona riservata ai puntatori, fino a quella riservata ai dati
    for( s=(int*)(dinamica+qr), i=0; i<qr*qc; i++ ) s[i]=i;
    printf("\nMatrice dinamica\nvisualizzata con routine\n");
    visualizza( dinamica+qr, qr, qc ); // con +qr passi oltre alla zona
                // riservata ai puntatori, fino a quella riservata ai dati

    printf( "\nMatrice dinamica\nvisualizzata direttamente\n" );
    for( r=0; r<qr; r++ )
        for ( c=0; c<qc; c++ )
            printf( "%02d%c", dinamica[r][c], c!=qc-1?' ':'\n' );

    free( dinamica ); // dealloco; avendo allocato un unico blocco, la
                      // deallocazione si risolve in un'unica chiamata
    return 0;
}


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 10/02 22: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.
11/02 11:54
Carlo
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:
#include <stdio.h>
#include <stdlib.h>

#define DIMr 5
#define DIMc 10

void visualizza(int m[DIMr][DIMc]){
    for (int r=0; r<DIMr; r++){
        printf("\n");
        for (int c=0; c<DIMc; c++) printf("%02d ", m[r][c]);
    }
    printf("\n\n");
}

int main(){
    int **dinamica=NULL, *ps=NULL, *pd=NULL, i;
    int statica[DIMr][DIMc];

    printf("statica 2dim riempita serialmente e visualizzata con routine a indici\n");
    ps=*statica; // ps punta l'inizio della matrice
    for (i=0; i<DIMr*DIMc; i++) ps[i]=i+1; // posso riempire serialmente, tabellina dell'1
    visualizza(statica); // funziona

    // alloco una matrice dinamica a due dimensioni con righe contigue
    dinamica=(int **) malloc(DIMr*sizeof(int *));
    dinamica[0]=(int*) malloc(DIMr*DIMc*sizeof(int));
    for (i=1; i<DIMr; i++) dinamica[i]=dinamica[0]+i*DIMc;

    printf("dinamica 2dim riempita serialmente e visualizzata con routine a indici\n");
    pd=*dinamica; // pd punta l'inizio della matrice
    for (i=0; i<DIMr*DIMc; i++) pd[i]=(i+1)*2; // posso riempire serialmente, tabellina del 2
    visualizza(pd); // funziona

    free(dinamica[0]);
    free(dinamica); 
    return 0;
}

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 26/02 23:09
in programmazione tutto è permesso
11/02 14:35
AldoBaldo
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.