Ist free (ptr), wo ptr NULL ist, ein beschädigter Speicher?

112

Theoretisch kann ich das sagen

free(ptr);
free(ptr); 

ist eine Speicherbeschädigung, da wir den bereits freigegebenen Speicher freigeben.

Aber was wenn

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

Da sich das Betriebssystem undefiniert verhält, kann ich keine tatsächliche theoretische Analyse darüber erhalten, was passiert. Was auch immer ich tue, ist das Gedächtnisbeschädigung oder nicht?

Ist das Freigeben eines NULL-Zeigers gültig?

Vijay
quelle
1
Ich bin mir nicht sicher über den C-freien Standard, aber in C ++ ist delete (NULL) vollkommen gültig, also denke ich, dass free (NULL) auch sein sollte.
Priyank Bolia
14
@Pryank: delete NULList in C ++ nicht gültig. delete kann auf Nullzeigerwerte vom konkreten Typ angewendet werden, nicht jedoch auf NULL. delete (int*) NULList legal, aber nicht delete NULL.
Am
es bedeutet also, wenn ein Zeiger auf NULL frei zeigt, führt nichts aus. Bedeutet das !!!!!! Jedes Mal in unserer Codierung, wenn Sie einen Speicher freigeben möchten, können Sie einfach ein freies (ptr) durch ptr = NULL ersetzen?
Vijay
3
Nein. Wenn Sie ptrauf den Speicher zeigen und ihn nicht aufrufen free, geht der Speicher verloren. Wenn Sie es NULLso einstellen, dass es nur den Speicher im Griff hat und undicht wird. Wenn ptr dies der FallNULL ist, freeist das Aufrufen kein Vorgang.
GManNickG
1
@benjamin: Huh? Was hat Sie zu dem Schluss , dass Sie ersetzen können free(ptr)mit ptr = NULL. Niemand sagte so etwas.
AnT

Antworten:

223

7.20.3.2 Die freeFunktion

Zusammenfassung

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

Beschreibung

Die freeFunktion bewirkt ptr, dass der freigegebene Speicherplatz freigegeben, dh für die weitere Zuweisung verfügbar gemacht wird. Wenn ptres sich um einen Nullzeiger handelt, wird keine Aktion ausgeführt.

Siehe ISO-IEC 9899 .

Wenn Sie sich jedoch verschiedene Codebasen in freier Wildbahn ansehen, werden Sie feststellen, dass die Leute manchmal Folgendes tun:

if (ptr)
  free(ptr);

Dies liegt daran, dass einige C-Laufzeiten (ich erinnere mich sicher, dass dies unter PalmOS der Fall war) beim Freigeben eines NULLZeigers abstürzen würden .

Aber heutzutage glaube ich, dass es sicher ist anzunehmen, dass es sich um free(NULL)ein Nein handelt, wie es der Standard vorschreibt.

Gregory Pakosz
quelle
29
Nein, ptr = NULL ist kein kostenloser Ersatz (ptr), beide sind völlig unterschiedlich
Prasoon Saurav
7
NEIN, es bedeutet, free(ptr)dass ptrNull keine Nebenwirkungen hat. Aber auf jeden Fall wird jeder Speicher, der mit verwendet wird malloc()oder calloc()danach freigegeben werden mussfree()
Gregory Pakosz
4
ptr = NULL stellt sicher, dass Ihr Programm auch dann nicht fehlerfrei wird, wenn Sie versehentlich free (ptr) aufrufen.
Prasoon Saurav
2
Bitte beachten Sie, dass der C-Standard zwar sagt, dass es sich um ein No-Op handelt, dies jedoch nicht bedeutet, dass jede C-Bibliothek so damit umgeht. Ich habe kostenlose Abstürze (NULL) gesehen, daher ist es am besten zu vermeiden, die kostenlosen überhaupt anzurufen.
Derick
6
@WereWolfBoy meint er zu vermeiden, free(NULL)indem er den Zeiger NULLvor dem Aufruf free()
testet
22

Alle standardkonformen Versionen der C-Bibliothek behandeln free (NULL) als No-Op.

Das heißt, zu einer Zeit gab es einige Versionen von Free, die auf Free (NULL) abstürzen würden, weshalb Sie möglicherweise einige defensive Programmiertechniken empfehlen:

if (ptr != NULL)
    free(ptr);
R Samuel Klatchko
quelle
8
-1 [Zitieren erforderlich]. Eine Änderung des Codestils aufgrund einer Theorie einer archaischen Hörensagenimplementierung ist eine schlechte Idee.
Tomas
41
@Tomas - Ich habe nie empfohlen, den Stil zu ändern. Ich habe lediglich erklärt, warum diese Empfehlung in einigen Stilen möglicherweise noch angezeigt wird.
R Samuel Klatchko
5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) und PalmOS für zwei (2. Hand für beide).
Douglas Leeder
7
@Tomas: Das Problem war in Sachen Version 7 Unix. Als ich lernte, war free (xyz), wobei xyz == NULL ein Rezept für eine sofortige Katastrophe auf dem Computer war, auf dem ich gelernt hatte (ICL Perq mit PNX, das auf Version 7 Unix mit einigen System III-Extras basierte). Aber ich habe lange nicht mehr so ​​codiert.
Jonathan Leffler
2
Netware stürzt auch bei der Freigabe von NULL ab ... (hat gerade einen Absturz
behoben
13

Wenn ptr NULL ist, wird keine Operation ausgeführt.

sagt die Dokumentation.

Michael Krelin - Hacker
quelle
Meinst du, dass der freie Wille nichts leistet?
Vijay
2
benjamin, genau das bedeutet es. Was würden Sie von ihm erwarten, wenn er sich der Nichtigkeit des Arguments bewusst ist?
Michael Krelin - Hacker
12

Ich erinnere mich, dass ich an PalmOS gearbeitet habe, wo es free(NULL)abgestürzt ist.

jlru
quelle
4
Interessant - das macht eine zweite Plattform (nach 3BSD) zum Absturz.
Douglas Leeder
2
Wenn ich mich richtig erinnere, existierte auf Palm die C-Standardbibliothek nicht. Stattdessen gab es eine meist nicht unterstützte Header-Datei, die Standardbibliotheksaufrufe dem Palm OS SDK zuordnete. Viele Dinge handelten unerwartet. Das Abstürzen NULLwar einer der großen Unterschiede zwischen der Palm-Toolbox und der Standardbibliothek.
Steven Fisher
8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Sie können einen NULL-Zeiger sicher löschen. In diesem Fall wird keine Operation ausgeführt. Mit anderen Worten, free () führt nichts an einem NULL-Zeiger aus.

Prasoon Saurav
quelle
8

Empfohlene Verwendung:

free(ptr);
ptr = NULL;

Sehen:

man free

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

Wenn Sie den Zeiger auf setzen, NULLnachdem free()Sie free()ihn erneut aufrufen können, wird keine Operation ausgeführt.

stefanB
quelle
3
Dies hilft auch dabei, Fehler mit einem Debugger zu erkennen. Es ist offensichtlich, dass segfault bei p-> do () mit p = 0 jemand ist, der einen freigegebenen Zeiger verwendet. Weniger offensichtlich, wenn Sie p = 0xbfade12 im Debugger sehen :)
Neuro
6

free(NULL)vollkommen legal ist auch in C wie delete (void *)0unddelete[] (void *)0 sind legal in C ++.

Übrigens verursacht das zweimalige Freigeben von Speicher normalerweise einen Laufzeitfehler, sodass nichts beschädigt wird.

n0rd
quelle
2
delete 0ist in C ++ nicht legal. deleteerfordert explizit einen Ausdruck vom Zeigertyp. Es ist legal, deleteauf einen typisierten Nullzeigerwert anzuwenden , jedoch nicht auf 0(und nicht auf NULL).
Am
1
Sie können auch nicht löschen void*: P Welche Destruktoren sollten ausgeführt werden?
GManNickG
1
@GMan: Sie können löschen void *, solange es sich um einen Nullzeiger handelt.
AnT
OK Fair genug. Ich habe vergessen, dass wir uns nur speziell mit Null befassen.
GManNickG
in der Regel beschädigt nichts, ist aber nicht garantiert. ASLR macht dies eher unwahrscheinlich, aber immer noch nicht unmöglich: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - Wenn Sie Pech haben, hat buf2 genau die gleiche Adresse wie buf1 erhalten, und Sie haben buf1 versehentlich zweimal befreit irgendein (sofortiger) Fehler / Absturz / was auch immer. (aber Sie werden wahrscheinlich immer noch einen Absturz bekommen, wenn Sie das nächste Mal versuchen, buf2 zu verwenden - und dieses Szenario ist sehr unwahrscheinlich, wenn Sie auf ASLR laufen)
hanshenrik
3

free(ptr)Speicher in C ist , wenn ptrist NULLjedoch, was die meisten Leute nicht wissen , das ist NULLnotwendig auf 0 nicht gleich sein ich ein nettes Altschule Beispiel habe: Auf dem C64, auf Adresse 0, gibt es einen IO-Ports. Wenn Sie ein Programm in C geschrieben haben, das auf diesen Port zugreift, benötigen Sie einen Zeiger mit dem Wert 0. Die entsprechende C-Bibliothek müsste zwischen 0 und NULLdann unterscheiden.

Mit freundlichen Grüßen.

andi8086
quelle
Interessante Tatsache, hat mich überrascht. Ich fühlte mich gezwungen, eine Reise durch NULL Zeiger Fragen / Antworten zu machen.
Arthropode
0

Keine Speicherbeschädigung, aber das Verhalten hängt von der Implementierung ab. Standardmäßig sollte es ein Gesetzbuch sein.

Pavel Radzivilovsky
quelle
-3

ptr zeigt auf einen Speicherort, sagen wir 0x100.

Wenn Sie (ptr) freigeben, erlauben Sie im Grunde, dass 0x100 vom Speichermanager für andere Aktivitäten oder Prozesse verwendet wird, und in einfachen Worten bedeutet dies, dass Ressourcen freigegeben werden.

Wenn Sie ptr = NULL ausführen, zeigt ptr auf eine neue Position (machen Sie sich keine Sorgen darüber, was NULL ist). Dadurch haben Sie den Überblick über die 0x100-Speicherdaten verloren. Dies ist ein Speicherverlust.

Es ist daher nicht ratsam, ptr = NULL für einen gültigen ptr zu verwenden.

Stattdessen können Sie eine sichere Überprüfung durchführen, indem Sie Folgendes verwenden:

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

Wenn Sie (ptr) freigeben, wobei ptr bereits auf NULL zeigt, wird keine Operation ausgeführt. Dies ist also sicher.

Kishanp
quelle