2016-05-19 8 views
5

Se una variabile era già malloc 'ed in passato, cosa succede se si chiama ancora malloc anziché realloc? Causerà una perdita di memoria?Cosa succede quando si chiama Malloc su una variabile esistente?

Mi piacerebbe sapere in modo che possa aggiungere assegni prima delle chiamate malloc ai parametri passati alle funzioni per evitare potenziali perdite.

void memtest(char **foo) 
{ 
     if (foo) 
       *foo = malloc(10); // Assuming *foo was already allocated in the past. 
} 

Devo fare sempre quanto segue?

void memtest(char **foo) 
{ 
     if (foo) { 
       if (*foo) { 
         free(*foo); 

         *foo = NULL; 
       } 

       *foo = malloc(10); 
     } 
} 
+0

La domanda sarebbe meglio se aggiungeste uno snippet di codice. – haccks

+1

Non esiste una cosa come "chiamare malloc su una variabile". – immibis

risposta

4

Non esiste una cosa come "chiamare malloc su una variabile".

malloc trova una memoria "libera", la contrassegna come "utilizzata" e restituisce l'indirizzo dell'inizio della memoria appena trovata. free contrassegna alcuni "usati" come "liberi".

Quando si esegue

*foo = malloc(10); 

avviene quanto segue:

  • malloc trova 10 byte di memoria libera.
  • malloc contrassegna quei 10 byte come usati.
  • malloc restituisce l'indirizzo dell'inizio dei 10 byte appena trovato.
  • Il programma visualizza il valore di foo, che è un indirizzo perché foo è un puntatore.
  • Il programma memorizza l'indirizzo malloc restituito, all'indirizzo memorizzato in foo.

malloc non potrebbe importare di meno ciò che fa il programma con l'indirizzo restituito. Non gli importa se il tuo programma lo memorizza in una semplice variabile, in un array, in un altro spazio di malloc o addirittura lo scrive in un file. Non importa nemmeno se il tuo programma dimentica l'indirizzo, ma dovresti aver cura, perché il tuo programma non sarà mai in grado di chiamare free se non conosce l'indirizzo della memoria che sta tentando di liberare.

Data questa conoscenza, si dovrebbe essere in grado di vedere cosa fa questo codice:

char *bar; 
bar = malloc(10); 
bar = malloc(10); 
free(bar); 

Prenditi il ​​tuo tempo per capirlo, allora continuate a leggere qui di seguito:

 

 

  • Una variabile denominata bar viene dichiarata ed. Il suo tipo è char*.
  • Il programma chiama malloc.
  • malloc trova 10 byte liberi e li contrassegna come utilizzati.
  • malloc restituisce l'indirizzo dell'inizio dei 10 byte.
  • Il programma memorizza l'indirizzo in bar. (bar ora contiene l'indirizzo dei primi 10 byte)
  • Il programma chiama malloc.
  • malloc trova 10 ulteriori byte liberi e li contrassegna come usati.
  • malloc restituisce l'indirizzo dell'inizio dei 10 byte.
  • Il programma memorizza l'indirizzo in bar. (bar ora contiene l'indirizzo dei secondi 10 byte)
  • Il programma chiama free e passa l'indirizzo dell'inizio dei secondi 10 byte.
  • free contrassegna i secondi 10 byte come liberi.

Questa è una perdita di memoria. I primi 10 byte non verranno mai liberati. Posso dire che non verranno mai liberati, perché il programma non sa in che indirizzo si trovano.

Ma che dire di questo programma?

char *bar; 
char *baz; 
bar = malloc(10); 

baz = bar; 
baz = malloc(10); 

Qui ho chiamato malloc "on" una variabile che era già in mano l'indirizzo di qualcosa malloc ed. Quindi questa è una perdita di memoria? Non da solo. Il programma potrebbe ancora free il primo blocco di memoria, il cui indirizzo è ancora memorizzato in baz.

Ma, questo è sicuramente una perdita di memoria:

void func() 
{ 
    char *bar; 
    char *baz; 
    bar = malloc(10); 

    baz = bar; 
    baz = malloc(10); 
} 

non ho ancora cambiato il codice, ma solo mettendo in una funzione, è ora una perdita di memoria! Whaaaaaaaaa?

Ricordare cosa è effettivamente una perdita di memoria. Una perdita di memoria è quando un programma alloca la memoria ma non la libera mai. Non si può sapere se un programma libera tutta la sua memoria semplicemente guardando le chiamate malloc.


Per quanto riguarda la seconda parte, "dovrei farlo?"

No, non si dovrebbe.

Esso funziona solo se il vecchio valore all'indirizzo passato alla funzione è un puntatore malloc ed, e se il chiamante è dimenticato di free esso.

tuo suggerimento si romperà una di queste funzioni:

void func1() 
{ 
    char c; 
    char *ptr = &c; 
    memtest(&ptr); // Tries to free something that wasn't malloced! 
    // ... do something with ptr ... 
} 
void func2() 
{ 
    char *ptr; 
    memtest(&ptr); // Passes a garbage address to free! 
    // ... do something with ptr ... 
} 
void func3() 
{ 
    char *ptr1 = malloc(5) 
    char *ptr2 = ptr1; 
    memtest(&ptr1); 
    // ... do something with ptr1 and ptr2 ... 
    free(ptr1); // Frees memory that was already freed! 
} 

in conclusione: la domanda nel titolo do non ha senso E rilevare perdite di memoria non è così semplice. E quello che stai cercando di fare è una cattiva idea.

+0

Mi sento come se avessi ricevuto automaticamente la risposta accettata solo dal fastidio di scrivere una lunga risposta. È stato davvero utile? – immibis

+0

Sto pensando la stessa cosa. Hai ottenuto la ricompensa per il tuo duro lavoro :) – haccks

+0

Sì, più scrivere più velocemente è la risposta accettata ... ahah;) Buona risposta a BTW. – LPs

5

Se il puntatore per *foo conteneva l'unico puntatore alla memoria allocata in precedenza, si è appena trapelata la memoria che c'era prima. Altrimenti, è completamente innocuo.

3

Provoca la perdita di memoria a causa del fatto che la precedente memoria allocata non viene indicata da alcuna variabile e l'indirizzo perso.

Non ci sono controlli specifici su questo. È possibile impostare il puntatore su NULL in dichiarazione e impostarlo su NULL ogni volta che la memoria è free ed. Quindi è possibile controllare if (pointer == NULL) prima di chiamare malloc.

Utilizzando realloc si potrebbe evitare problemi di perdita di memoria, perché se il puntatore è un puntatore nullo, la funzione realloc si comporta come la funzione malloc per le dimensioni speci fi cato. Ma potrebbe causare problemi se il tuo puntatore non è dichiarato impostato su NULL.

cioè .:

int *foo = NULL; 

void bar(void) 
{ 
    foo = realloc(foo, 10*sizeof(int)); 
} 

Una caratteristica buona o cattiva di realloc è esso preservare il contenuto della vostra memoria.

Devo fare sempre quanto segue?

void memtest(char **foo) 
{ 
     if (*foo) 
       free(*foo); 

     *foo = malloc(10); 
} 

No si dovrebbe non a causa di free non impostare il puntatore NULL e se il puntatore hanno ancora il valore di un free di memoria ed il break già programma con l'errore. Intendo dire che un tale codice è soggetto ad errori nel caso in cui il tuo puntatore si trovi da qualche parte nel codice senza ridistribuire lo free. E devi assicurarti che il puntatore sia dichiarato con NULL come valore iniziale.

+0

Questo mi fa meravigliare: perché avere 'malloc' in primo luogo, allora? Tutti possono sempre usare 'realloc'. Ovviamente, si dovrebbe avvolgere l'intero blocco del corpo della funzione in un controllo "if" per assicurarsi che il puntatore stesso non sia "NULL". – Mahouk

+0

È, secondo la mia opinione personale, avere un codice più leggibile. Voglio dire usare 'realloc' solo quando state riallocando qualcosa precedentemente' malloc'ated e dove volete preservare il contenuto della memoria. Ma puoi usare 'realloc' solo in un intero codice e un singolo libero. – LPs

1

Cosa succede quando si chiama malloc su una variabile esistente?

Ci sono poche possibilità:

  • Se la memoria è allocata con successo dal precedente malloc poi ri allocazione di memoria causerà perdita di memoria.
  • Se in qualsiasi modo l'allocazione della memoria con la precedente chiamata malloc non è riuscita, non si verificherà alcuna perdita di memoria.

Devo fare sempre quanto segue?

void memtest(char **foo) 
{ 
     if (*foo) 
       free(*foo); 
     *foo = malloc(10); 
} 

Sì. In questo modo non si verificano perdite di memoria.

+0

'free' non imposta il puntatore su' NULL' quindi 'if (* foo) libero (* pippo);' è sbagliato. Mi manca qualcosa? – LPs

+0

@LPs; 'if (* foo)' sta controllando se la precedente chiamata di 'malloc' ha avuto successo. Nel caso in cui fosse fallito, 'malloc' deve aver restituito' NULL'. Quindi, se '* foo' non punta a' NULL' quindi libera il blocco di allocazione. Nota che' * pippo' viene liberato dopo aver controllato '* pippo' per' NULL'. – haccks

+0

Intendevo dire che se in un'altra parte del codice la memoria è libera e non allocata, una funzione come quella non riesce. – LPs

5

La chiamata a malloc è irrilevante.

Il problema è il compito, se c'è un problema. Dopo aver eseguito x=42;, il valore precedente di x non è più disponibile, indipendentemente dall'importanza che avrebbe potuto avere. Allo stesso modo, se foo è l'unico puntatore che hai memoria, se sovrascrivi foo, non hai più accesso a quella memoria.

Non è possibile chiamare free senza specificare cosa liberare. Quindi, se non hai liberato la memoria prima di aver perso l'unico puntatore che hai avuto, non sarai mai in grado di liberarla, che è la definizione di una perdita di memoria.