Free (ptr) dove ptr è la memoria corrotta NULL?


112

Teoricamente posso dirlo

free(ptr);
free(ptr); 

è un danneggiamento della memoria poiché stiamo liberando la memoria che è già stata liberata.

Ma cosa succede se

free(ptr);
ptr=NULL;
free(ptr); 

Poiché il sistema operativo si comporterà in modo indefinito, non posso ottenere un'analisi teorica effettiva di ciò che sta accadendo. Qualunque cosa stia facendo, è questa corruzione della memoria o no?

La liberazione di un puntatore NULL è valida?


1
non sono sicuro dello standard C free, ma in C ++ delete (NULL) è perfettamente valido, quindi immagino che dovrebbe essere anche free (NULL).
Priyank Bolia

14
@Pryank: delete NULLnon è valido in C ++. delete può essere applicato ai valori del puntatore nullo di tipo concreto, ma non a NULL. delete (int*) NULLè legale, ma non lo è delete NULL.
AnT

quindi significa che se un puntatore punta a NULL free non esegue nulla. significa !!!!!! ogni volta nella nostra codifica se si vuole liberare una memoria si può semplicemente sostituire un free (ptr) con ptr = NULL?
Vijay

3
No. Se ptrpunta alla memoria e non la richiami free, la memoria perderà. Impostandolo su si NULLperde il controllo della memoria e si perde. Se ptr succedeNULL , la chiamata freeè una non operazione.
GManNickG

1
@benjamin: eh? Cosa ti ha fatto concludere che puoi sostituire free(ptr)con ptr = NULL. Nessuno ha detto niente del genere.
AnT

Risposte:


224

7.20.3.2 Il free funzione

Sinossi

#include <stdlib.h> 
void free(void *ptr); 

Descrizione

La freefunzione fa sì che lo spazio puntato da ptrvenga deallocato, ovvero reso disponibile per un'ulteriore allocazione. Se ptrè un puntatore nullo, non viene eseguita alcuna azione.

Vedere ISO-IEC 9899 .

Detto questo, guardando diversi codebase in natura, noterai che a volte le persone fanno:

if (ptr)
  free(ptr);

Questo perché alcuni runtime C (ricordo di sicuro che era il caso su PalmOS) si bloccavano quando si liberava un NULLpuntatore.

Ma al giorno d'oggi, credo che free(NULL)sia lecito ritenere che sia un nop secondo le istruzioni dello standard.


29
No, ptr = NULL non è assolutamente un sostituto gratuito (ptr), entrambi sono completamente diversi
Prasoon Saurav

7
NO, significa che free(ptr)dove ptrè nullo non ha effetti collaterali. Ma in ogni caso, ogni memoria allocata utilizzando malloc()o calloc()deve essere rilasciata successivamente utilizzandofree()
Gregory Pakosz

4
ptr = NULL assicura che anche se si chiama accidentalmente free (ptr) il programma non verrà segfault.
Prasoon Saurav,

2
Si noti che sebbene lo standard C dica che non è un'operazione, ciò non significa che ogni libreria C lo gestisca in quel modo. Ho visto arresti anomali gratuiti (NULL), quindi è meglio evitare di chiamare il free in primo luogo.
Derick

6
@WereWolfBoy intende evitare free(NULL)testando il puntatore contro NULLprima di chiamarefree()
Gregory Pakosz

22

Tutte le versioni conformi agli standard della libreria C trattano free (NULL) come no-op.

Detto questo, un tempo c'erano alcune versioni di free che si bloccavano gratuitamente (NULL), motivo per cui potresti vedere alcune tecniche di programmazione difensive consigliate:

if (ptr != NULL)
    free(ptr);

8
-1 [citazione necessaria]. Cambiare lo stile del codice a causa di alcune teorie di un'implementazione arcaica per sentito dire è una cattiva idea.
Tomas,

41
@Tomas - Non ho mai consigliato di cambiare stile, ho semplicemente spiegato perché potresti ancora vedere questo consiglio in alcuni stili.
R Samuel Klatchko

5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) e PalmOS per due (seconda mano per entrambi).
Douglas Leeder

7
@Tomas: il problema era in cose come la versione 7 Unix. Quando stavo imparando, gratis (xyz) dove xyz == NULL era una ricetta per il disastro istantaneo sulla macchina in cui ho imparato (ICL Perq che esegue PNX, che era basato sulla versione 7 Unix con alcuni extra di System III). Ma non codifico in questo modo da molto tempo.
Jonathan Leffler

2
Netware si arresta in modo anomalo anche quando si libera NULL ... (ha appena eseguito il debug di un arresto anomalo su di esso ...)
Calmarius

13

Se ptr è NULL, non viene eseguita alcuna operazione.

dice la documentazione.


vuoi dire che gratuitamente non eseguirà nulla?
Vijay

2
Benjamin, è esattamente quello che significa. Cosa ti aspetteresti che esegua se fosse a conoscenza della nullità dell'argomento?
Michael Krelin - hacker

12

Ricordo di aver lavorato su PalmOS dove si è free(NULL)schiantato.


4
Interessante: questo fa sì che una seconda piattaforma (dopo 3BSD) si blocchi.
Douglas Leeder

2
Se ricordo bene, su Palm la libreria standard C non esisteva. Invece, c'era un file di intestazione per lo più non supportato che mappava le chiamate della libreria standard attraverso il Palm OS SDK. Molte cose hanno agito in modo imprevisto. Il crash su è NULLstata una delle grandi differenze di esecuzione del toolbox Palm rispetto alla libreria standard.
Steven Fisher

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

È possibile eliminare in modo sicuro un puntatore NULL. Nessuna operazione verrà eseguita in quel caso, in altre parole free () non fa nulla su un puntatore NULL.


8

Utilizzo consigliato:

free(ptr);
ptr = NULL;

Vedere:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

Quando si imposta il puntatore su NULLdopo, free()è possibile richiamarlo di free()nuovo e non verrà eseguita alcuna operazione.


3
Ciò aiuta anche a individuare i segfault con un debugger. È evidente che il segfault in p-> do () con p = 0 è qualcuno che usa un puntatore liberato. Meno evidente quando vedi p = 0xbfade12 nel debugger :)
neuro

6

free(NULL)è perfettamente legale in C così come delete (void *)0e delete[] (void *)0sono legali in C ++.

A proposito, liberare due volte la memoria di solito causa una sorta di errore di runtime, quindi non danneggia nulla.


2
delete 0non è legale in C ++. deleterichiede esplicitamente un'espressione di tipo puntatore. È legale applicare deletea un valore di puntatore nullo digitato, ma non a 0(e non a NULL).
AnT

1
Non è possibile eliminare void*nessuno dei due: P Quali distruttori dovrebbe eseguire?
GManNickG

1
@GMan: puoi cancellare void *fintanto che è un puntatore nullo.
AnT

Ok, abbastanza giusto. Ho dimenticato che abbiamo a che fare specificamente solo con null.
GManNickG

di solito non danneggia nulla, ma non è garantito. ASLR lo rende piuttosto improbabile, ma ancora non impossibile: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - qui se sei sfortunato, buf2 ha lo stesso identico indirizzo di buf1, e hai liberato accidentalmente buf1 due volte, quindi il 2 ° libero da buf1 hai effettivamente liberato buf2 silenziosamente, senza mai scrivere qualsiasi (immidate) errore / crash / qualunque cosa. (ma probabilmente si verificherà comunque un arresto anomalo la prossima volta che proverai a utilizzare buf2 - e questo scenario è molto improbabile se
utilizzi

3

free(ptr)è salvo in C se ptrè NULL, tuttavia, ciò che la maggior parte delle persone non sa è che NULLnon deve essere uguale a 0. Ho un bell'esempio della vecchia scuola: sul C64, all'indirizzo 0, c'è una porta IO. Se hai scritto un programma in C che accede a questa porta, avresti bisogno di un puntatore il cui valore è 0. La libreria C corrispondente dovrebbe distinguere tra 0 e NULLpoi.

Cordiali saluti.


Fatto interessante, mi ha colto di sorpresa. Mi ha fatto sentire obbligato a fare un viaggio intorno alle domande / risposte del puntatore NULL.
artropodi

0

non il danneggiamento della memoria, ma il comportamento dipende dall'implementazione. Di norma, dovrebbe essere un codice legale.


-3

ptr punta a una posizione di memoria, diciamo 0x100.

Quando si libera (ptr), in pratica si consente a 0x100 di essere utilizzato dal gestore della memoria per altre attività o processi e in parole semplici si tratta di deallocazione di risorse.

Quando fai ptr = NULL, stai facendo in modo che ptr punti a una nuova posizione (non preoccuparti di cosa sia NULL). In questo modo hai perso traccia dei dati di memoria 0x100, che è la perdita di memoria.

Quindi non è consigliabile usare ptr = NULL su un ptr valido.

Invece potresti fare qualche controllo sicuro usando:

if (ptr! = NULL) {free (ptr);}

Quando si libera (ptr) dove ptr sta già puntando a NULL, non esegue alcuna operazione, quindi è sicuro farlo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.