Versuchen Sie, free() zu verwenden, um zu verstehen, wie es funktioniert

Lesezeit: 7 Minuten

Benutzer-Avatar
Benutzer3314983

Um die Verwendung von free in der Programmiersprache C zu verstehen, habe ich versucht, diesen Code auf Ubuntu auszuführen, aber beim Ausführen der EXE-Datei erhalte ich einen SIGABRT-Fehler. Warum wird das Programm nicht normal beendet?

#include<stdio.h>
#include<stdlib.h>

int main()
{
   int ret;
   int *ptr;
   ptr = (int *)malloc(sizeof(int)*10);
   free(ptr);
   ptr = &ret;
   free(ptr);
   return 0;
}

  • Statische Zuordnung automatisch zurückgefordert. Nicht erforderlich free es.

    – Jayesh Bhoi

    14. April 2014 um 5:21 Uhr


  • Sie müssen den Rückgabewert von nicht umwandeln malloc in einem C-Programm.

    – Karl Norum

    14. April 2014 um 5:21 Uhr

  • Sie gehen nie zu free ein Wert, der nicht von zurückgegeben wurde malloc(), calloc(), realloc()oder eine Funktion, die Ihnen einen Zeiger auf Speicher zurückgibt, der “als ob” von einer dieser Funktionen zugewiesen wurde (z strdup(), getline(), asprintf(), scanf() mit dem %ms Modifikator usw.).

    – Jonathan Leffler

    14. April 2014 um 5:24 Uhr

  • Wie bist du gekommen und gelaufen, an EXE Datei auf Ubuntu?

    – Elliot Frisch

    14. April 2014 um 18:47 Uhr


  • free ist die “un-malloc”-Funktion, nicht die “free any memory”-Funktion.

    – Benutzer253751

    15. April 2014 um 5:51 Uhr

Benutzer-Avatar
Karl Norum

Versuch, einen Zeiger zu befreien, von dem Sie nicht gekommen sind malloc (oder einer seiner Freunde) verursacht undefiniertes Verhalten. Dein zweiter free(ptr) Anruf versucht genau das.

Aus der C-Spezifikation, §7.22.3.3 Die free FunktionAbsatz 2:

Das free Funktion verursacht das Leerzeichen, auf das von gezeigt wird ptr freigegeben werden, d. h. für eine weitere Zuweisung verfügbar gemacht werden. Wenn ptr ein Nullzeiger ist, findet keine Aktion statt. Andernfalls, 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 reallocist das Verhalten undefiniert.

Benutzer-Avatar
Alexander Ach

Während alle undefinierten Verhaltensantworten richtig sind, könnte es hilfreicher sein, eine Implementierung zu sehen.

Ich denke, ein sehr guter Hinweis darauf ist K&R C malloc. Eine Erklärung, wie es funktioniert, ist in “Die Programmiersprache C”Kapitel 8.7.

Denken Sie beim Betrachten von Code aus Standardbibliotheksfunktionen in C daran, dass sie eine Implementierung und eine Spezifikation haben, wobei die Implementierung möglicherweise ein reproduzierbares Verhalten aufweist, das von ihrer Spezifikation nicht gefordert wird.

Eigentlich fast alle malloc Implementierungen haben eine freie Liste, wo sie freie Speicherbereiche in einer Liste (oder mehreren Listen) verwalten. Die kostenlose Liste wird oft so gehandhabt, dass das Aufrufen free mehrfach auf einen Speicherbereich versetzt diese Liste in einen falschen Zustand.

Auch böswilliges Verhalten kann hervorgerufen werden, wenn Datenstrukturen gezielt erstellt werden. Phrack hat einen veralteten Artikel darüber, wie die Codeausführung aufgerufen wird, wenn ungültiger Speicher an übergeben wird free während die Freelist beschädigt wird.

Andere Malloc-Implementierungen könnte auch einen Blick wert sein (dies ist eine unvollständige Liste von Zuordnungsbibliotheken).

Benutzer-Avatar
Mahonri Moriancumer

   ptr = &ret;
   free(ptr);

ist das gleiche wie:

    free(&ret);

ret befindet sich auf dem Stack, nicht auf dem Heap. Versuchen free() Speicher, der nicht allokiert wurde (mit malloc()usw.) auf dem Heap führt zu undefiniertem Verhalten.

  • In jedem mir bekannten Fall führt dies zu einem Laufzeitfehler.

    – Mahonri Moriancumer

    16. April 2014 um 4:54 Uhr

  • @RiaD: Jede Plattform, an der ich gearbeitet habe, gibt einen Laufzeitfehler aus. Plattformen müssen dies jedoch nicht (z. B. sehr eingeschränkte eingebettete Systeme, die ohne Betriebssystem ausgeführt werden), und undefiniertes Verhalten wird häufig missverstanden ( blog.regehr.org/archives/213 ), es bedeutet etwas ganz anderes als “Ihr Betriebssystem wird sich beschweren”.

    – Max Lybbert

    4. Juni 2014 um 19:39 Uhr

  • @MaxLybbert, nun, mein Kommentar befasste sich mit der Zeile “wird einen Laufzeitfehler verursachen” in der Antwort, die jetzt herausgeschnitten wird

    – RiAD

    4. Juni 2014 um 20:59 Uhr

  • Ich wusste, dass die Antwort schon eine Weile da war, und ich hatte weder von Ihnen noch von @MahonriMoriancumer eine Antwort erwartet. Ich möchte einfach klarstellen, dass “undefiniertes Verhalten” viel mehr bedeutet als “plötzlicher Absturz”. Es könnte bedeuten, dass “der Compiler Ihren Code ändert und das Endergebnis möglicherweise nicht einmal in der Originalsprache beschreibbar ist”.

    – Max Lybbert

    4. Juni 2014 um 21:59 Uhr

Benutzer-Avatar
Ashraful Haque

Die Funktion free() funktioniert nur für den zugewiesenen Speicher heap durch malloc(). Nicht für die statische Zuordnung, da statische Zuordnungen automatisch behandelt werden. Hier ist der Fehler:

 int ret; 

 ptr = &ret;

 free(ptr);

Sie können dies nicht tun, weil der Speicher für ret wird nicht auf dem Heap allokiert. Es befindet sich im Stack und nur der Speicher des Heaps sollte freigegeben werden.

Benutzer-Avatar
Rahul Tripathi

Dein zweiter free(ptr) verursacht undefiniertes Verhalten, wenn Sie versuchen, einen Zeiger freizugeben, den Sie nicht zugewiesen haben. Beachten Sie auch, dass statische Zuweisungen automatisch zurückgefordert werden, sodass Sie sie nicht freigeben müssen.

Benutzer-Avatar
Jeegar Patel

  ptr = &ret;
   free(ptr);

Hier versuchen Sie, den Speicher der lokalen Speicherstapelvariablen freizugeben. In der Regel sollten Sie es nicht freigeben. Wenn main() beendet wird, wird immer der gesamte lokale Speicher auf dem Stack frei.

Free funktioniert nur mit Heap-Allokationsspeicher.

Benutzer-Avatar
Gesetzentwurf IV

Es gibt drei Bereiche, in denen Variablen in einem AC- oder C++-Programm erstellt werden können.

  • globale oder statische Variablen befinden sich an festen Stellen in der ausführbaren Binärdatei.
  • automatische Variablen außerhalb des statischen Gültigkeitsbereichs befinden sich auf dem Stack
  • malloc’ed oder calloc’ed Variablen befinden sich auf dem Heap.

free() ist die Funktion, die zuvor zugewiesenen Speicher auf dem Heap freigibt. Ein Zeiger auf den Speicher auf dem Heap wird von malloc oder ähnlichen Funktionen zurückgegeben. Die einzige Möglichkeit, diesen Speicher zu lesen oder zu schreiben, ist über den Zeiger. Ein Zeiger ist eine Adresse, und ein Zeiger* ist der Inhalt, auf den an dieser Adresse gezeigt wird.

In dem gezeigten Beispiel gibt es zwei Variablen, die in Main definiert und effektiv statisch sind, und den zurückgegebenen Wert von Main, der sich auf dem Stack befindet. Unter Verwendung der minimalen Ganzzahl, 16 Bit, ist hier eine mögliche Speicherabbildung. In dieser Karte beginnen die Anweisungen bei 0, der Stapel beginnt bei einem Wert ungleich Null (Beginn des Stapels – bos) und wächst durch Inkrementieren, und ein Heap beginnt bei der maximalen Adresse (…FFFF, auch bekannt als -1). und wächst durch dekrementieren:

(Denken Sie daran, MIN_INT ist -32768, MAX_INT ist 32767 … die Spezifikation garantiert nur 16 Bits, signiert)

Jedes Byte hat eine Adresse, die ‘n’ Bits breit ist – typischerweise 16, 32 oder 64 Bits


-1. (Start of Heap, z. B. 16-Bit-Adresse: 0xFFFF, 32-Bit-Adresse: 0xFFFFFFFF oder 64-Bit-Adresse: 0xFFFFFFFFFFFFFFFF)

-2. (1. Stelle nach unten vom Anfang des Haufens. 0x…FFFE) ptr[ 9 ]auf einmal

-3. (2. Stelle nach unten vom Beginn des Haufens. 0x…FFFD)

-4. (3. Stelle ab Beginn des Haufens. 0x…FFFC) ptr[ 8 ]auf einmal

[snip]

-17. (16. Stelle nach unten vom Anfang des Haufens. 0x…FFEF)

-18. (17. Stelle ab Beginn des Haufens. 0x…FFEE) ptr[ 1 ]auf einmal

-19. (18. Stelle nach unten vom Beginn des Haufens. 0x…FFED)

-20 (19. Stelle ab Beginn des Haufens. 0x…FFEC) ptr[ 0 ]auf einmal

-21. (Top of Heap, 10 x 16 Bit Ints nach unten vom Anfang des Heaps. 0x … FFEB), auf einmal

: Ein sehr großer Adressbereich auf 32- oder 64-Bit-Rechnern… :

tos: ( Stapelspitze 0x…tos )

bos + ( sizeof( int ) – 1) Ende von int zurückgegeben von Main()

bos: (Beginn des Stacks: über statischen Daten ) Beginn von int zurückgegeben von Mail()

togs: (Anfang von global/statisch) Ende von „ptr“

: (Größe eines Zeigers ist die Breite des Adressbusses … was auch immer nötig ist)

togs-(n-1): (top of global/static – (sizeof( int* ) – 1)) start of “ptr”

(togs-n) : Ende von “ret”

(togs-n)-1: Beginn von “ret”

(alle globalen Dinge, die der Compiler für sich selbst hinzufügt, den Debugger usw.)

(Ende des Programmcodes)

(Beginn des Programmcodes)

(Anfang des Nicht-Programmcodes)

0 (Beginn des Nichtprogrammcodes, 0x…0000 )


Zur Laufzeit beginnen “ptr” und “ret” wahrscheinlich beide bei ‘0’, da es sich um feste, statische Werte handelt, die aus der Datei gelesen werden, aus der die ausführbare Binärdatei stammt.

Während das Programm läuft, ändert sich der Wert von “ptr”, um zuerst auf den Heap zu zeigen, auf das mallocierte Array von 10 Ints: “0x…FFEC”

Der Aufruf von free() ändert den Wert von ptr nicht, es ist immer noch “0x…FFEC”. Das Freigeben von “0x…FFEC” ist legitim und läuft ohne irgendetwas Komisches.

Die Zuweisung “ptr = &ret” setzt einen neuen Wert in “ptr”, “(togs-n)-1”, den Beginn von “ret”.

Das Freigeben von “(togs-n)-1” verursacht einen sofortigen Absturz, weil “frei” den Wert von “(togs-n)-1” prüft und dieser NICHT im gültigen Bereich für eine Heap-Adresse liegt.

“ret” bleibt leer, es wird nie gesetzt, aber da es global/statisch ist, bleibt es so, wie es war, als der Linker es auf die Festplatte geschrieben hat.

1344830cookie-checkVersuchen Sie, free() zu verwenden, um zu verstehen, wie es funktioniert

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

Privacy policy