allocazione dinamica matrici

Stato
Discussione chiusa ad ulteriori risposte.

Frank2000

Nuovo Utente
26
0
Ho creato una struttura chiamata matrice così definita :
Codice:
typedef struct
{
   double **matrice;   /* Matrice */
   int    num_righe;   /* Numero righe della matrice */
   int    num_colonne; /* Numero colonne della matrice */
} matrice_t;
Poi ho creato una funzione che ne fa l'allocazione dinamica , dopo aver inserito il numero di righe e colonne :
Codice:
void alloca_matrice(matrice_t *mat)
{
   int i;

   /* alloca le righe */

   mat-> matrice = (double **)calloc(mat-> num_righe,sizeof(double *));

   /* alloca le colonne */

   for (i=0;
        i < mat->num_righe;
    i++)
   {
            mat-> matrice[i] = (double *)calloc(mat-> num_colonne,sizeof(double));

   }

}
Poi ho fatto una funzione per inserire dati nella matrice :
C:
void riempi_matrice(matrice_t *mat)
{
   int i,
       j;

   for (i=0;
        i < mat->num_righe;
    i++)
   {
         for(j=0;
             j < mat->num_colonne;
         j++)
         {
             printf("Inserisci l'elemento nella %d riga e %d colonna ---> ",
                    i + 1, j + 1);
             scanf("%lf",&mat->matrice[i][j]);
         }
   }
            
}
E infine una funzione che stampa la matrice :
C:
void stampa_matrice(matrice_t *mat)
{
   int i,
       j;

   for (i=0;
        i < mat->num_righe;
    i++)
   {
       printf("\n");
   }
          for(j=0;
              j < mat->num_colonne;
          j++)
          {
          printf("%f\t",
                 mat->matrice[i][j]);
      }
}
Solo che in esecuzione, fino alla funzione che stampa sembra andare tutto bene, ma quando deve stampare la matrice si crea un errore di segmentazione e quindi l'esercuzione non va a buon termine. Non riesco a trovare l'errore, un aiutino?
 

AntonioRagagnin

Nuovo Utente
13
11
C'`e un typo:
sulla funzione stampa_matrice, il blocco di codice del for(j=0.. non e' all'interno del blocco di codice di for(i=0...
(vedi che chiudi la parentesi grafa appena prima di for(j=0.. )
 
Ultima modifica:
  • Mi piace
Reazioni: BrutPitt

BrutPitt

Utente Attivo
1,166
1,262
Come ha scritto @AntonioRagagnin il problema e' proprio nella chiusura della parentesi, a quel punto "i" e' gia' di una unita' fuori range (essendo i==mat->num_righe), da li' il sementation-fault.

In realta' intervengo per dire che sarebbe buona norma (proprio per questo motivo) utilizzare le variabili "internamente" al ciclo for, qualcosa come:
C++:
void stampa_matrice(matrice_t *mat)
{
   for (int i=0;
        i < mat->num_righe;
    i++)
   {
       printf("\n");
   }
          for(int j=0;
              j < mat->num_colonne;
          j++)
          {
          printf("%f\t",
                 mat->matrice[i][j]);
      }
}

Il codice e' il TUO, quello errato, ma in questo modo il compilatore riporta un errore, essendo la "i" uscita dal campo di visibilita'.
 
  • Mi piace
Reazioni: AntonioRagagnin

Frank2000

Nuovo Utente
26
0
okay grazie mille! E poi dovrei usare alla fine della funzione main la free giusto? ma a cosa serve esattamente?
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
okay grazie mille! E poi dovrei usare alla fine della funzione main la free giusto? ma a cosa serve esattamente?
La funzione free() serve a liberare la memoria allocata dinamicamente con malloc, calloc o realloc. A ciascuna malloc/calloc/realloc deve corrispondere una free quando la memoria allocata non serve più. Altrimenti, si ha un memory leak, ovvero della memoria che resta allocata ma non è più accessibile e utilizzabile perché il puntatore che la referenziava non punta più ad essa o non esiste più.
 
  • Mi piace
Reazioni: Gigyyt e BAT

nullptr

Nuovo Utente
34
9
A ciascuna malloc/calloc/realloc deve corrispondere una free quando la memoria allocata non serve più. Altrimenti, si ha un memory leak, ovvero della memoria che resta allocata ma non è più accessibile e utilizzabile perché il puntatore che la referenziava non punta più ad essa o non esiste più.
Questo non è vero: posso ad esempio adoperare realloc() più di una volta senza chiamare esplicitamente free() (a meno che fallisca restituendo NULL, in questo caso ne ho bisogno) dato che automaticamente libera il vecchio blocco di memoria (ricorre già a free() per la memoria indirizzata dall'indirizzo del puntatore) e restituisce un nuovo blocco di memoria allocata, ed è questa che dovrai alla fine liberare.
Se provassi poi ad usare malloc(), libero la memoria (come hai già detto tu) e vado di realloc() (che si sarebbe già premurato da solo del free()) ho un undefined behavior perchè provi a servirti di un'area già liberata.
E non necessariamente si ha un memory leak se eventualmente non si dealloca la memoria prima che il programma termini: molti sistemi operativi la disimpegnano automaticamente.
 
Ultima modifica:

BAT

Moderatore
Staff Forum
Utente Èlite
22,918
11,562
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
E non necessariamente si ha un memory leak se eventualmente non si dealloca la memoria prima che il programma termini: molti sistemi operativi la disimpegnano automaticamente.
Vero, tuttavia trascurare tale pratica perché "lo fa il sistema operativo" non è corretto:
innanzitutto non si ha mai la certezza che il sistema rilasci correttamente le risorse, in secondo luogo è parte integrante delle pratiche di buona programmazione quando lavori in C/C++ che ti lasciano "libero accesso" alla gestione della memoria.
Il messaggio è: intanto cominciamo a scrivere NOI codice che sia "ben fatto" (per quanto possibile ed alla portata delle nostre conoscenza).

Perfino in Java, dove la gestione di memoria è a carico del linguaggio, può succedere che essa non venga rilasciata correttamente. E dire che il garbage-collector è scritto da un intero team di specialisti che, in questi ambiti, ne sanno 100 volte di più di un programmatore bravo.
 
  • Mi piace
Reazioni: Mursey

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Questo non è vero: posso ad esempio adoperare realloc() più di una volta senza chiamare esplicitamente free() (a meno che fallisca restituendo NULL, in questo caso ne ho bisogno) dato che automaticamente libera il vecchio blocco di memoria (ricorre già a free() per la memoria indirizzata dall'indirizzo del puntatore) e restituisce un nuovo blocco di memoria allocata, ed è questa che dovrai alla fine liberare.
Se provassi poi ad usare malloc(), libero la memoria (come hai già detto tu) e vado di realloc() (che si sarebbe già premurato da solo del free()) ho un undefined behavior perchè provi a servirti di un'area già liberata.
E non necessariamente si ha un memory leak se eventualmente non si dealloca la memoria prima che il programma termini: molti sistemi operativi la disimpegnano automaticamente.
In effetti sono stato impreciso. Intendevo dire che ci vuole una free dopo l'ultima realloc. Davo per scontato il fatto che non si deve chiamare free tra più realloc consecutive (d'altra parte altrimenti che senso avrebbe realloc, basterebbe usare malloc/calloc, come in C++ che ci sono solo new e delete e non l'equivalente di realloc), o tra una malloc/calloc e una realloc, dato che chiamando free senza poi assegnare NULL al puntatore, questi punterà ancora all'area di memoria precedentemente allocata (dangling pointer).
 

nullptr

Nuovo Utente
34
9
Vero, tuttavia trascurare tale pratica perché "lo fa il sistema operativo" non è corretto:
innanzitutto non si ha mai la certezza che il sistema rilasci correttamente le risorse, in secondo luogo è parte integrante delle pratiche di buona programmazione quando lavori in C/C++ che ti lasciano "libero accesso" alla gestione della memoria.
L'unica differenza fra me è te è la seguente: ti stai frastornando con cose che non c'entrano in quanto il sistema operativo gestisce le risorse, termine molto vagante che hai scelto in quanto stiamo parlando specificamente di memoria, e realisticamente parlando in quel caso nessun brano di memoria va perduto. Un free() subito prima di uscire dal programma, diventa inutile se svolto correttamente (potrebbe dipendere pure dal sistema operativo, come ho già detto).
Il messaggio è: intanto cominciamo a scrivere NOI codice che sia "ben fatto" (per quanto possibile ed alla portata delle nostre conoscenza).
Sempre parlando di non svolgere free() espressamente prima di uscire dal programma, e rispettando le condizioni che ho già specificato precedentemente, il codice non ha assolutamente niente di male. Ciò che invece vorresti dire è che nel caso un qualsivoglia memory debugger lo rilevi come memory leak, potrebbe aggrovigliare leggermente le tue idee se il tuo programma ne presenta ulteriori.
innanzitutto non si ha mai la certezza che il sistema rilasci correttamente le risorse
Inizia ad utilizzare i termini adeguati: stiamo parlando di sistema operativo. Sbagliato pure dire che non si abbia "mai" la certezza, quello che dici tu potrebbe succedere nel caso che il sistema operativo fallisca nella gestione delle risorse (o più specificamente il sistema operativo potrebbe andare pure in stato deadlock), ma molto verosimilmente lì ci sarà un crash senza mezzi termini.

Ma poi il mio intervento era riferito solo ed esclusivamente al fatto che non si avrà un memory leak, e qualsiasi altra cosa tu stia tentando da dire, ciò che ho detto è commisurato con un "non necessariamente". Niente di scorretto, ciò che ho detto è giusto, alla soglia giusta.

questi punterà ancora all'area di memoria precedentemente allocata (dangling pointer).
Altra inesattezza: un pointer non è un'area di memoria, bensì una variable che conserva un indirizzo di memoria. Solo quest'ultimo poi punta ad un'area di memoria, e ciò mi porta a dirti che non ti serve imparare la tiritera di queste tre funzioni a memoria... volevo solo farti capire quanto come la tua definizione fosse mendace. La via corretta per dare quelle definizioni è garantirsi prima di sapere cosa facciano quelle funzioni interiormente e strutturalmente.
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Altra inesattezza: un pointer non è un'area di memoria, bensì una variable che conserva un indirizzo di memoria. Solo quest'ultimo poi punta ad un'area di memoria, e ciò mi porta a dirti che non ti serve imparare la tiritera di queste tre funzioni a memoria... volevo solo farti capire quanto come la tua definizione fosse mendace. La via corretta per dare quelle definizioni è garantirsi prima di sapere cosa facciano quelle funzioni interiormente e strutturalmente.
Non ho scritto che un puntatore è un'area di memoria, ma che punta ad un'area di memoria, cioè ne contiene l'indirizzo della prima locazione (non a caso si chiamano puntatori). Conscio della differenza che c'è tra indirizzi di memoria e puntatori, non mi sembra sbagliato dire che un puntatore, in virtù del fatto che contiene un indirizzo di memoria, punta alla cella di memoria avente quell'indirizzo.
 
  • Mi piace
Reazioni: BAT

nullptr

Nuovo Utente
34
9
Non ho scritto che un puntatore è un'area di memoria, ma che punta ad un'area di memoria, cioè ne contiene l'indirizzo della prima locazione (non a caso si chiamano puntatori). Conscio della differenza che c'è tra indirizzi di memoria e puntatori, non mi sembra sbagliato dire che un puntatore, in virtù del fatto che contiene un indirizzo di memoria, punta alla cella di memoria avente quell'indirizzo.
La tua è solo una similitudine, che in certi casi trasfigura in qualcosa di impreciso. Un puntatore è una variabile, l'indirizzo di memoria del puntatore è ben differente ed è il suo valore che "punta" ad un altro indirizzo di memoria. Se per esempio il pointer è NULL (si potrebbe avere magari altra roba non valida) il tuo traslato perde del tutto significato in quanto si ha un puntatore che non punta a nulla.
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,918
11,562
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Ho fatto una semplice considerazione di buona pratica di programmazione: se puoi liberare la memoria, meglio liberarla, se puoi uccidere un thread inutile uccidilo, ecc. ecc. Guarda caso, la memoria è una "risorsa" di sistema (operativo). Giuro che non intendevo offendere sua signoria, anche perché mi pareva palesemente chiaro cosa volessi dire.
Sorvolo sulle tue inutili e provocatorie puntualizzazioni agli interventi di @fabio93 che giornalmente tenta di aiutare gli altri utenti del forum (da te usato esclusivamente per mettere in ridicolo chiunque tenti di contribuirvi).
 
Ultima modifica:

nullptr

Nuovo Utente
34
9
Ho fatto una semplice considerazione di buona pratica di programmazione: se puoi liberare la memoria, meglio liberarla
Grazie per la pappardella, ma se continui a ripetermi che sia necessario (o pessima pratica non ->) liberare la memoria prima che il programma termini dimostri soltanto di non avere alcuna idea (o non aver letto) su cosa stia facendo il sistema operativo dietro le quinte.
Tralasciando la disamina dei memory leak:
Ciò che invece vorresti dire è che nel caso un qualsivoglia memory debugger lo rilevi come memory leak, potrebbe aggrovigliare leggermente le tue idee se il tuo programma ne presenta ulteriori.
ripeto, concettualmente qui liberare la memoria non ha senso perchè viene già disimpegnata dall'OS: quest'ultimo deve essere già adibito per farlo autonomamente anche solo per un ipotetico crash.

E credo di essermi spiegato bene pure qui:
Ma poi il mio intervento era riferito solo ed esclusivamente al fatto che non si avrà un memory leak, e qualsiasi altra cosa tu stia tentando da dire, ciò che ho detto è commisurato con un "non necessariamente".

ma non è nemmeno il punto della discussione, ovviamente questi sono i soliti interventi per andare fuori tema ed è grave vizio e difetto da parte tua. Fatti più sveglio e impara a focalizzarti sull'obiettivo senza altri diversivi.

se puoi uccidere un thread inutile uccidilo, ecc. ecc.
Uccidere? Per l'ennesima volta ti invito a parlare con un linguaggio tecnico, a meno che dovesse prenderti di gradimento fare immagini metaforiche con omicidi.

Sorvolo sulle tue inutili e provocatorie puntualizzazioni agli interventi di @fabio93 che giornalmente tenta di aiutare gli altri utenti del forum (da te usato esclusivamente per mettere in ridicolo chiunque tenti di contribuirvi).
Se vuoi vedere una legittima correzione come "mettere in ridicolo", hai una concezione dei fatti alquanto inetta: non può essere altro che benefica per un lettore... e nonostante certe definizioni siano state date in modo approssimativo (a meno che tu stia inesattamente pensando che siano corrette), errare humanum est. Nessuna provocazione.

P.S: Per favore, evita il dileggio arbitrario ("sua signoria") perchè dimostri poca serietà a differenza di quanto ne stia mostrando io ora nell'argomento.
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,918
11,562
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
...solo che io parlavo di principi generali di buona programmazione, astraendomi dal caso specifico.

Non dai alcun contributo costruttivo al forum e non ne hai minimamente compreso lo spirito.
Visto che tanto ti piace rimanere nello specifico: in questo thread non hai aiutato l'utente che ha posto il quesito, ti sei limitato a criticare, pignoleggiare e puntualizzare ogni singola frase degli altri interventi.

Complimenti vivisimi, continua così.
 
  • Mi piace
Reazioni: AntonioRagagnin

nullptr

Nuovo Utente
34
9
...solo che io parlavo di principi generali di buona programmazione, astraendomi dal caso specifico.
Credo che perlomeno tu stesso abbia capito quanto fosse stato intempestivo, fuori luogo ed errato il tuo intervento in quanto si stava parlando di una cosa ben specifica.

Non dai alcun contributo costruttivo al forum e non ne hai minimamente compreso lo spirito.
Visto che tanto ti piace rimanere nello specifico: in questo thread non hai aiutato l'utente che ha posto il quesito, ti sei limitato a criticare, pignoleggiare e puntualizzare ogni singola frase degli altri interventi.
Riguardo al problema di @Frank2000, credo che abbia già risolto sin dall'inizio per quanto l'errore fosse insignificante. Successivamente ho sentito la necessità di riprendere le definizioni riportategli poichè abbastanza impetuose (per la domanda sul free()), se questo non è costruttivo dovresti elaborare di più quando argomenti.
Non tutti sono così abbacinati quanto al contrario tu manifesti di essere, dato che tutto vedi (insulti, provocazioni, critiche, ecc.) tranne che qualche nozione sulla gestione dinamica della memoria.
Al contrario, molto poco sensato e ostico si è rivelato il tuo commento, poichè completamente fuori luogo e non spettante a ciò che è stato richiesto dall'utente (quando va usato il free()).
 
Stato
Discussione chiusa ad ulteriori risposte.

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili