Auf einen Zeiger zweimal kostenlos telefonieren

Lesezeit: 6 Minuten

Benutzer-Avatar
Jo

Diese Berufung wurde mir in Vorlesungen beigebracht free() auf einem Zeiger zweimal ist wirklich, wirklich schlecht. Ich weiß, dass es gute Praxis ist, einen Zeiger darauf zu setzen NULLdirekt nach der Befreiung.

Allerdings habe ich noch nie eine Erklärung gehört, warum das so ist. Soweit ich weiß, der Weg malloc() funktioniert, sollte es technisch gesehen die Zeiger verfolgen, die es zugewiesen und Ihnen zur Verwendung gegeben hat. Warum weiß es also nicht, ob es einen Pointer durch bekommt free() wurde schon befreit oder nicht?

Ich würde gerne verstehen, was intern passiert, wenn Sie anrufen free() an einem zuvor bereits freigegebenen Ort.

  • Der Zeiger ist nur dort, wo Sie die Richtung der Daten annotieren, aber was Sie tatsächlich freigeben, sind die Daten selbst

    – Netwave

    15. Dezember 2015 um 9:01 Uhr

  • @DanielSanchez Ja, aber da malloc Ihnen diesen Zeiger zuwirft, sollte das Konstrukt zum Freigeben/Zuweisen von Speicher nicht immer noch bemerken, dass es den Ort freigegeben hat, auf den der Zeiger zuvor zeigt?

    – Jo

    15. Dezember 2015 um 9:03 Uhr

  • Wenn Sie den Zeiger nicht nach Ihnen verwenden free es hat keinen Sinn, es darauf einzustellen NULL. Und wenn Sie verwenden den Zeiger nach Ihnen free es hast du undefiniertes Verhalten egal ob du es einstellst NULL oder nicht. Natürlich, wenn Sie überprüfen zum NULL dann hilft es, aber man muss einen zeiger dazu setzen NULL ist etwas, das Sie nicht unbedingt tun müssen, tun Sie dies von Fall zu Fall, je nachdem, wie Sie den Zeiger verwenden.

    – Irgendein Programmierer-Typ

    15. Dezember 2015 um 9:04 Uhr

  • Es könnte suchen, um zu sehen, ob sich der freigegebene Block bereits in der Liste der freien Blöcke befindet, aber dies würde Programme verlangsamen, die diese Funktionalität nicht benötigen

    – MM

    15. Dezember 2015 um 9:07 Uhr

  • Sie können sich den Heap-Speicher ansehen, der von verwaltet wird malloc und free als Wasserbecken. Wenn Sie Speicher mit zuweisen malloc Du bekommst einen Löffel Wasser und kannst damit machen, was du willst. Wenn du free Wenn die Erinnerung die Wasserschaufel zurück in den Pool gießt, verlieren Sie den Überblick darüber, welche Erinnerung Ihnen gehört, und der Speichermanager auch. Durch das Freigeben des Speichers wird nur Ihr Scoop geleert, aber Sie behalten immer noch den eigentlichen Scooper (Zeiger).

    – Irgendein Programmierer-Typ

    15. Dezember 2015 um 9:07 Uhr


Wenn Sie verwenden malloc Sie teilen dem PC mit, dass Sie einen Speicherplatz auf dem Heap nur für Sie reservieren möchten. Der Computer gibt einen Zeiger auf das erste Byte des adressierten Raums zurück.

Wenn Sie verwenden free Sie teilen dem Computer tatsächlich mit, dass Sie diesen Speicherplatz nicht mehr benötigen, sodass er diesen Speicherplatz als für andere Daten verfügbar markiert.

Der Zeiger zeigt immer noch auf diese Speicheradresse. An diesem Punkt kann derselbe Platz im Heap von einem anderen zurückgegeben werden malloc Anruf. Wenn Sie aufrufen free ein zweites Mal geben Sie nicht die vorherigen Daten frei, sondern die neuen Daten, und dies ist möglicherweise nicht gut für Ihr Programm 😉

  • Vielen Dank für die Erklärung!

    – Jo

    15. Dezember 2015 um 9:19 Uhr

Benutzer-Avatar
Sourav Ghosh

Um deine erste Frage zu beantworten,

Warum weiß es also nicht, ob es einen Pointer durch bekommt free() wurde schon befreit oder nicht?

weil die Spezifikation für malloc() im C-Standard schreibt dies nicht vor. Wenn du anrufst malloc() oder Familie von Funktionen, was es tut, ist, Ihnen einen Zeiger zurückzugeben und intern die Größe des zugewiesenen Speicherplatzes zu speichern in dieser Zeiger. Das ist der Grund free() benötigt keine Größe, um den Speicher zu bereinigen.

Auch einmal free()-d, was passiert mit der eigentlich Der zugewiesene Speicher ist immer noch implementierungsabhängig. Berufung free() ist nur ein Marker um darauf hinzuweisen, dass der zugewiesene Speicher nicht mehr vom Prozess verwendet wird und bei Bedarf zurückgefordert und neu zugewiesen werden kann. Daher ist es an diesem Punkt sehr unnötig, den zugewiesenen Zeiger zu verfolgen. Es wird eine unnötige Belastung für das Betriebssystem sein, es beizubehalten alle die Backtracks.

Zu Debugging-Zwecken können jedoch einige Bibliotheksimplementierungen diese Aufgabe für Sie übernehmen, wie DUMA oder dmalloc und nicht zuletzt das Memcheck-Tool von Valgrind.

Jetzt, technischdas C Standard gibt kein Verhalten vor, wenn Sie anrufen free() auf einen bereits freigegebenen Zeiger. es ist undefiniertes Verhalten.

C11Kapitel §7.22.3.3, free() Funktion

[…] wenn das Argument nicht mit einem Zeiger übereinstimmt, der zuvor von einer Speicherverwaltungsfunktion zurückgegeben wurde, oder wenn der Speicherplatz durch einen Aufruf von freigegeben wurde free() oder realloc()ist das Verhalten undefiniert.

Benutzer-Avatar
hackt

C-Standard sagt nur diese Berufung free zweimal auf einen von zurückgegebenen Zeiger malloc und seine Familienfunktion rufen undefiniertes Verhalten hervor. Es gibt keine weitere Erklärung, warum das so ist.
Aber warum es schlecht ist, wird erklärt hier:

Den gleichen Chunk zweimal befreien

Um zu verstehen, was diese Art von Fehler verursachen kann, sollten wir uns daran erinnern, wie der Speichermanager normalerweise funktioniert. Oft speichert es die Größe des zugewiesenen Chunks direkt vor dem Chunk selbst im Speicher. Wenn wir den Speicher freigegeben haben, wurde dieser Speicherblock möglicherweise von einem anderen erneut zugewiesen malloc() Anfrage, und damit diese doppelt frei wird tatsächlich den falschen Speicherblock freigeben – was dazu führt, dass wir an einer anderen Stelle in unserer Anwendung einen baumelnden Zeiger haben. Solche Fehler zeigen sich in der Regel viel später als an der Stelle im Code, an der sie aufgetreten sind. Manchmal sehen wir sie überhaupt nicht, aber sie lauern immer noch herum und warten auf eine Gelegenheit, ihre hässlichen Köpfe zu erheben.

Ein weiteres Problem, das auftreten könnte, ist, dass dies doppelt frei erfolgt, nachdem der freigegebene Chunk mit benachbarten freien Chunks zusammengeführt wurde, um einen größeren freien Chunk zu bilden, und dann der größere Chunk neu zugewiesen wurde. In einem solchen Fall, wenn wir es versuchen free() unser Chunk zum 2. Mal verwenden, geben wir tatsächlich nur einen Teil des Speicherblocks frei, den die Anwendung derzeit verwendet. Dies wird noch mehr unerwartete Probleme verursachen.

Wenn Sie anrufen malloc Du bekommst einen Hinweis. Die Laufzeitbibliothek muss den Überblick behalten mallocEd Speicher. Typisch malloc speichert die Speicherverwaltungsstrukturen nicht getrennt von den malloc ed Speicher, aber an einem Ort. Also ein malloc für x Bytes dauert tatsächlich x + n Bytes, wobei ein mögliches Layout darin besteht, dass die ersten n Bytes eine verknüpfte Listenstruktur mit Zeigern auf den nächsten (und möglicherweise vorherigen) zugewiesenen Speicherblock enthalten.

Wenn du free ein Zeiger dann die Funktion free könnte durch seine internen Speicherverwaltungsstrukturen gehen und prüfen, ob der Zeiger, den Sie übergeben, ein gültiger Zeiger ist, der war malloced. Nur dann konnte es auf die verborgenen Teile des Speicherblocks zugreifen. Diese Überprüfung wäre jedoch sehr zeitaufwändig, insbesondere wenn Sie viel zuweisen. So free geht einfach davon aus, dass Sie einen gültigen Zeiger übergeben. Das heißt, es greift direkt auf die verborgenen Teile des Speicherblocks zu und geht davon aus, dass die Zeiger der verknüpften Liste dort gültig sind.

Wenn du free einen Block zweimal, dann hast du vielleicht das Problem, dass jemand einen neuen gemacht hat mallochat den Speicher, den Sie gerade freigegeben haben, überschrieben und den zweiten free liest daraus ungültige Zeiger.

Einstellung a freed Zeiger auf NULL ist eine gute Übung, weil es beim Debuggen hilft. Wenn Sie zugreifen freed-Speicher kann Ihr Programm abstürzen, aber es kann auch nur verdächtige Werte lesen und später abstürzen. Dann kann es schwierig sein, die Ursache zu finden. Wenn Sie einstellen freed Zeiger auf NULL Ihr Programm stürzt sofort ab, wenn Sie versuchen, auf den Speicher zuzugreifen. Das hilft enorm beim Debuggen.

1251720cookie-checkAuf einen Zeiger zweimal kostenlos telefonieren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy