Allocazione memoria Matrice

di il
9 risposte

Allocazione memoria Matrice

Ciao a tutti,
sono arrivato alla MALLOC! e tra gli esercizi mi viene chiesto di allocare la memoria per una matrice.
ci sono riuscito creando una matrice, o meglio un puntatore a puntatori **matrice
nella fase di allocazione però ho avuto difficoltà e ho trovato delle spiegazioni sul web che mi hanno permesso di concludere l'esercizio ma non mi spiegavano esaustivamente il funzionamento.
int main (void)
{
    int **matrice;             
    int x,y;
    int i,j;
    printf("quante righe? ");
    scanf("%d",&x);
    printf("quante colonne? ");
    scanf("%d",&y);
    
    matrice=malloc(x*sizeof *matrice);              <<<<<<<<<< quesito 1       
    for (i=0;i<y;i++){                                      
        matrice[i]=malloc(x*sizeof **matrice);             <<<<<<<<<<<<<quesito 2
        if (matrice[i]==NULL){                              
            return -1;
        }
    }
    for (i=0;i<x;i++){
        for (j=0;j<y;j++){                                  
            matrice[i][j]=rand()%999;
            printf("[%d][%d]%3d ",i,j,matrice[i][j]);
        }
        printf("\n");
    }
    for (i=0;i<x;i++){                                   
        free(matrice[i]);                            <<<<<<<<<<<< quesito 3 
    }
    free(matrice);                                      
}
                                                           
                                                            
vquesito 1: normalmente alloco una dimensione pari a (x * sizeof(int)) mentre qui ho allocato (x*sizeof *matrice). leggendolo potrei pensare che lo spazio da allocare è pari al valore che ho chiesto da tastiera, identificabile come il numero di celle del primo array, la "riga", moltiplicato per la la dimensione dell'array.
A questo punto è allocata la memoria di tutta la matrice???

quesito 2: qui mi sembra di allocare la memoria di tutti gli array, tutte le righe, della matrice.
ecco, ma se ho già allocato tutta la matrice nel punto prima? al quesito 1....
non capisco, mi sembrano 2 cose "uguali", o meglio, mi sembra più completa la seconda, quella del quesito 2...

quesito 3: perché la free deve avvenire simmetricamente? forse con la spiegazione dei primi 2 quesiti qui ci arriverei anche solo...

grazie a tutti, qui trovo sempre tante persone competenti che mi danno sempre un ottimo aiuto!!

9 Risposte

  • Re: Allocazione memoria Matrice

    1) Dal punto di vista logico, la premessa è sbagliata. Devi fare:
    
    matrice = malloc (x* sizeof(int*));
    
    Questo perché a te interessa avere una riga di int* non di matrice*. Che poi il sizeof() ritorni lo stesso valore perché entrambi sono puntatori è incidentale.

    2) Ti sembra più completa perché è quella corretta. Nel punto 1 allochi solo una riga, non l'intera matrice. Ora devi allocare le varie colonne e lo fai così:
    
    matrice[i] = malloc (y * sizeof(int));
    
    3) Il C non ha il garbage collector (e aggiungo per fortuna), per cui liberare la memoria è a carico del programmatore. E il modo è esattamente l'inverso dell'allocazione. Prima si libera la memoria delle varie colonne, poi della riga iniziale, concettualmente come in uno stack: l'ultimo allocato è il primo da deallocare.
  • Re: Allocazione memoria Matrice

    Ciao,
    cominciamo a dire che quello che hai scritto è sbagliato, quindi ti spiego la logica corretta e se poi hai altri dubbi e/o domande da fare lo facciamo sull'esempio corretto.

    Quando vogliamo allocare una matrice dinamica, per comodità nella gestione, è preferibile usare una tabella di puntatori che punta all'allocazione effettiva. In pratica abbiamo una matrice di puntatori.Da qualche parte avevo letto un'analogia che diceva qualcosa tipo: "per cercare un numero di telefono cerchiamo il nome sull'agenda della persona da chiamare".
    Anche in questo caso, usiamo un vettore di puntatori per indirizzarci sul vettore effettivo.
    In schema tipo:
    
    RIGA           
     0 ---------> {c1,c2,c3... cn}
     1 ---------> {c1,c2,c3... cn}
     2 ---------> {c1,c2,c3... cn}
    
    Dove RIGA è la nostra matrice di puntatori che punta al vettore di COLONNE.

    Avremo:
    
    // Allochiamo la matrice di puntatori per le righe
    matrice=malloc(RIGHE * sizeof (int *));
    
    // Allochiamo la matrice per le colonne ed assegniamo l'indirizzo sulla matrice delle righe
    for (i=0;i<RIGHE;i++){                                      
       matrice[i]=malloc(COLONNE * sizeof (int));
            if (matrice[i]==NULL){                              
                return -1;
            }
        }
    
    
    Sperando di averti chiarito i dubbi ti auguro buona domenica

    EDIT:
    quoto shodan che mi ha anticipato nella mia pausa pranzo sottolineando il suo punto (3)
  • Re: Allocazione memoria Matrice

    Grazie per le risposte!
    allora, ho fatto le modifiche, il programma gira e termina eseguendo tutto ma mi da un errore EXC_BAD_ACCESS
    secondo me è su come libero la memoria...
        for (i=0;i<x;i++){                                     
            free(matrice[i]);
        }
        free(matrice);
  • Re: Allocazione memoria Matrice

    L'indice che hai usato per le colonne è y non x.
    
    for (i=0;i< y ;i++){                                     
            free(matrice[i]);
        }
        free(matrice);
    
    Edit.
    Probabilmente x e y hanno valori diversi, per cui vai a liberare memoria che non c'entra niente.
  • Re: Allocazione memoria Matrice

    Io userei un approccio diverso sull'allocazione della matrice. Guarda sto esempio:
    
    int x = 5;
    int y = 10;
    
    int **matrix = (int **)malloc(x * sizeof(int*)); // 1
    int *matrix_data = (int *)malloc(x * y * sizeof(int)); //2
    
    for (int i=0; i < x; i++, matrix_data+=y)
          matrix[i] = matrix_data;  //3
    
    free(matrix[0]);
    free(matrix);
    
    Prima si alloca spazio per le righe (punto 1). poi allochi tutto lo spazio che servirebbe a tutta la matrice quindi (x*y) (punto 2).
    Poi nel punto 3 assegni alla riga i-esima il posto dove puntare. Ad ogni assegnazione incrementi di y il puntatore della nuova riga.
    Questo comporta un'assegnazione più omogenea della memoria (chiami una volta il malloc invece che x-volte)
    Nella fase di eliminazione hai solo due free. Uno per tuttla matrice e uno per i puntatori delle righe.
  • Re: Allocazione memoria Matrice

    A dire il vero è sufficiente la 2 per allocare l'intera matrice. Giocando poi con gli indici si riesce ad accedere all'intero spazio allocato. E in genere si fa così proprio per evitare millemila malloc() e free(). La contro indicazione più evidente, però, è la perdita dell'accesso naturale con [x][y] a favore di una sintassi [y * x + i ], sicuramente più criptica, ma più efficiente (in effetti va meglio in C++ tramite opportuni overload di operator() ).

    Diciamo che il sistema "classico" per le matrici dinamiche è quello "scolastico", che prima o poi viene abbandonato in favore di quello più "professionale".
  • Re: Allocazione memoria Matrice

    @skynet
    Bello! Questo mi è piaciuto, mantieni la memoria compatta e continui ad accedere in maniera comoda con [x][y]. Interessante anche il free(matrix[0]) puoi farti una funzione per allocare e ti tieni un solo puntatore.
  • Re: Allocazione memoria Matrice

    A dire il vero è sufficiente la 2 per allocare l'intera matrice. Giocando poi con gli indici si riesce ad accedere all'intero spazio allocato. E in genere si fa così proprio per evitare millemila malloc() e free(). La contro indicazione più evidente, però, è la perdita dell'accesso naturale con [x][y] a favore di una sintassi [y * x + i ], sicuramente più criptica, ma più efficiente (in effetti va meglio in C++ tramite opportuni overload di operator() ).
    Condivido. Un alternativa meno criptica potrebbe essere usare una MACRO o meglio una funzione:
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #define M(y,x) *(m+((y)*(c))+(x))
    int main ()
    {
      int r=7,c=14,x,y;
      int *m=malloc(r*c*sizeof(int));
      
      for (y=0;y<r;y++)
    	for (x=0;x<c;x++)
    	  M(y,x)=rand()%999;
    	
      for (y=0;y<r;y++)
    	for (x=0;x<c;x++)
    	  printf ("m[%d][%d]=%d\n",y,x,M(y,x));
    
      free (m);
      
      return 0;
    }
    
    Ma, credo che a livello scolastico è corretto apprendere il primo metodo o il secondo proposto dall'amico skynet
  • Re: Allocazione memoria Matrice

    Grazie a tutti per i chiarimenti!

    sono ancora alle prime armi e queste spiegazioni mi sono utili per capire le possibili differenze per la stessa operazione.
    Devo dire che il livello scolastico con [x][y] mi è al momento più chiaro, ma questo è dovuto alle mie conoscenze ancora ridotte. Sto comunque cercando di capire a fondo gli altri metodi proposti e sicuramente riguarderò questa discussione diverse volte man mano che le mie esperienze aumenteranno.

    Colgo l'occasione per ringraziarvi davvero tutti, siete sempre molto esaustivi nell'aiutarmi a capire
Devi accedere o registrarti per scrivere nel forum
9 risposte