Richtige Verwendung von realloc()

Lesezeit: 8 Minuten

Benutzer-Avatar
Benutzer3163420

Von man realloc: Die Funktion realloc() gibt einen Zeiger auf den neu zugewiesenen Speicher zurück, der für jede Art von Variable geeignet ausgerichtet ist und vielleicht anders als ptr, oder NULL, wenn die Anfrage fehlschlägt.

Also in diesem Codeschnipsel:

ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){           //reallocated pointer ptr1
    printf("Exiting!!\n");
    free(ptr);
    exit(0);
}else{
    free(ptr);          //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
    ptr = ptr1;         //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address                     
}

Reicht es aus, einfach anzunehmen, dass der neu zugewiesene Zeiger auf einen anderen Speicherblock zeigt und nicht auf denselben Block? ausführt (aus dem in den Kommentaren angegebenen Grund), dann würde der Speicherblock gelöscht und das Programm würde verrückt werden. Soll ich eine andere Bedingung einfügen, die die Gleichheit von ptr und ptr1 vergleicht und die Ausführung der free(ptr)-Anweisung ausschließt?

Benutzer-Avatar
Aaron S. Kurland

Nur nicht anrufen free() auf deinem ursprünglichen ptr auf dem glücklichen weg. Im Wesentlichen realloc() hat das für dich erledigt.

ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{       
    printf("\nExiting!!");
    free(ptr);
    exit(0);
}
else
{
    ptr = ptr1;           // the reallocation succeeded, we can overwrite our original pointer now
}

  • In der Manpage von realloc konnte ich die Information nicht finden, dass es selbst free() aufrufen würde … thnx sowieso

    – Benutzer3163420

    8. Januar 2014 um 21:32 Uhr

  • @ user3163420 Wirklich? Auf meinem Mac man realloc: “… Wenn nicht genug Platz vorhanden ist, um die Speicherzuweisung zu vergrößern, auf die ptr zeigt, erstellt realloc() eine neue Zuweisung, kopiert so viele der alten Daten, auf die ptr zeigt, wie in die neue Zuweisung passen, gibt die alte Zuweisung und gibt einen Zeiger auf den zugewiesenen Speicher zurück. …”

    – Bedeutungsangelegenheiten

    8. Januar 2014 um 21:34 Uhr

  • Gießen Sie nicht das Ergebnis von malloc und realloc.

    – Emlai

    28. September 2015 um 10:39 Uhr

  • heh … die Typumwandlungen sind nicht nur ein Dorn im Auge, sondern könnten auf einigen obskuren Systemen Probleme verursachen und keinen Zweck erfüllen … aber Sie haben sie beibehalten, um den ursprünglichen Code zu erhalten. Jetzt wurden Leerzeichen eingeführt, um es weniger zu einem Schandfleck zu machen, die auch keinen funktionalen Zweck erfüllen, aber nichts kaputt machen (im Gegensatz zu Typumwandlungen, die dies tun werden). Mein Punkt ist, ob Sie zulassen würden, dass Leerzeichen hinzugefügt werden, um den Code zu erstellen stilistisch ansprechendwürden Sie auch zulassen, dass unnötige Typumwandlungen entfernt werden, um den Code zu erstellen tragbarer zusätzlich zu stilistisch ansprechend? Ich werde nicht bearbeiten, aber würdest du zurückgehen, wenn ich es täte?

    – autistisch

    29. April 2018 um 15:22 Uhr

  • /me schreit “Onkel!”. Abgüsse entfernt.

    – Aaron S. Kurland

    8. August 2018 um 15:32 Uhr

Benutzer-Avatar
Kieler

Anwenden von Korrekturen als Bearbeitungen, basierend auf den guten Kommentaren unten.

Lektüre diese comp.lang.c Frageenthüllt 3 Fälle:

  1. “Wenn es dazu in der Lage ist, gibt es Ihnen einfach denselben Zeiger zurück, den Sie ihm gegeben haben.”
  2. “Aber wenn es zu einem anderen Teil des Speichers gehen muss, um genügend zusammenhängenden Platz zu finden, wird es einen anderen Zeiger zurückgeben (und der vorherige Zeigerwert wird unbrauchbar).”
  3. “Wenn realloc kann überhaupt nicht genug Platz finden, gibt es einen Nullzeiger zurück und lässt die vorherige Region zugewiesen.”

Dies kann direkt in Code übersetzt werden:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3, clean up then terminate.
    free(ptr);
    exit(0);
}
else if(tmp == ptr)
{
    // Case 1: They point to the same place, so technically we can get away with
    // doing nothing.
    // Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
    tmp = NULL;
}
else
{
    // Case 2: Now tmp is a different chunk of memory.
    ptr = tmp;
    tmp = NULL;
}

Wenn Sie also darüber nachdenken, ist der von Ihnen gepostete Code (fast) in Ordnung. Der obige Code vereinfacht sich zu:

int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
    // Case 3.
    free(ptr);
    exit(0);
}
else if(ptr != tmp)
{
    ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;

Beachten Sie das Extra else if(ptr != tmp)was Fall 1 ausschließt, in dem Sie nicht anrufen möchten free(ptr) Weil ptr und tmp beziehen sich auf die gleiche Stelle. Nur zur Sicherheit stelle ich sicher, dass ich zuweise NULL zu tmp um Probleme mit baumelnden Zeigern zu vermeiden tmp liegt im Geltungsbereich.

  • Sie haben den Teil “und der vorherige Zeigerwert wird unbrauchbar” nicht befolgt. In dem ptr != tmp Fall, der free(ptr) ist falsch.

    – glglgl

    19. Juni 2017 um 15:28 Uhr

  • Stimme @glglgl zu, dass diese Antwort gefährlich ist, da du in Fall 2 nicht free(ptr) anrufen darfst.

    – Benutzer7761803

    5. September 2017 um 13:35 Uhr

  • Guter Anruf, angewendet als Bearbeitung und Kommentar-Upvotes für Sie beide.

    – Kieler

    5. September 2017 um 22:14 Uhr

  • @Keeler +1 zum Setzen des tmp-Zeigers auf NULL. Ich bin nur schwer gebissen worden, als ich einen neu zugewiesenen Zeiger innerhalb einer Funktion in statisch geändert habe. Das verursachte einen späteren Segfault mit nachfolgenden Realloc-Aufrufen (Speicher wurde zwischen Funktionsaufrufen freigegeben), da der Zeiger jetzt seinen alten (hängenden) Wert behielt. Ich habe eine Weile gebraucht, um es herauszufinden … Ich habe die Angewohnheit, Realloc oft über Malloc zu verwenden, aber man muss wachsam sein, um sicherzustellen, dass der erste Realloc-Aufruf (ohne vorheriges Malloc) einen NULL-Zeiger erhält.

    – DeutscherNerd

    21. März 2019 um 9:26 Uhr

  • Ich denke, dass exit(1) hier besser geeignet wäre.

    – Herr

    23. April um 15:28 Uhr

Benutzer-Avatar
Chux – Wiedereinsetzung von Monica

OP: … kann sich von ptr unterscheiden oder NULL sein, wenn die Anfrage fehlschlägt.
A: Nicht immer. NULL kann rechtmäßig zurückgegeben werden (kein Fehler), wenn count ist 0.

OP: Reicht es aus, einfach anzunehmen, dass der neu zugewiesene Zeiger auf einen anderen Speicherblock und nicht auf denselben Block zeigt.
A: Nein

OP: Soll ich eine andere Bedingung einfügen, die die Gleichheit von ptr und ptr1 vergleicht und die Ausführung der free(ptr)-Anweisung ausschließt?
A: Nein.

Wenn realloc() kehrt zurück NULL (und count ist nicht 0), der Wert von ptr ist immer noch gültig und zeigt auf die nicht in der Größe geänderten Daten. free(ptr) oder nicht, hängt von Ihren Zielen ab.

Wenn realloc() kehrt nicht zurück NULLunterlassen Sie free(ptr)es ist alles bereit befreit.

Beispiel: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper

#include <assert.h>
#include <stdlib.h>

int ReallocAndTest(char **Buf, size_t NewSize) {
  assert(Buf);
  void *NewBuf = realloc(*Buf, NewSize);
  if ((NewBuf == NULL) && (NewSize > 0)) {
    return 1;  // return failure
  }
  *Buf = NewBuf;
  return 0;
}

Benutzer-Avatar
Paulo Bu

realloc wird dieselbe Adresse zurücksenden ptr wenn es genug Platz hat, um den eigentlichen Speicherbereich zu erweitern, auf den verwiesen wird ptr. Andernfalls werden die Daten in den neuen Chunk verschoben und der alte Chunk freigegeben. Darauf kann man sich nicht verlassen ptr1 anders zu sein ptr. Ihr Programm verhält sich undefiniert.

Wenn realloc eine andere Adresse zurückgibt, wird zuerst die Zuordnung der alten aufgehoben, sodass Sie dies nicht selbst tun müssen.

Übrigens, werfen Sie niemals die Rückkehr von malloc/realloc :). Ihr Code sollte so aussehen:

ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{   
    // error!    
    printf("\nExiting!!");
    // no need to free, the process is exiting :)
    exit(0);
}

Wenn realloc Ihre Daten verschiebt, wird der alte Zeiger hinter den Kulissen für Sie freigegeben. Ich habe keine Kopie des C11-Standards, aber es ist im C99-Standard garantiert.

  • Der C11-Standardentwurf ist n1570.pdf, den Sie durch googeln finden können. Ich finde es hilfreich, mit Links zu zitieren (z Klicken Sie auf diesen Link bringt Sie zum realloc Abschnitt von n1570.html, der aus n1570.pdf konvertiert wurde).

    – autistisch

    2. Januar 2016 um 22:39 Uhr

Benutzer-Avatar
Johannes Bode

Du solltest nicht free Ihr ursprünglicher Zeiger, wenn die realloc gelingt es. Ob sie free dieser Zeiger, wenn die realloc fehlschlägt, hängt von den Anforderungen Ihrer speziellen Anwendung ab; wenn du absolut nicht weitermachen Ohne diesen zusätzlichen Speicher wäre dies ein schwerwiegender Fehler und Sie würden den gehaltenen Speicher freigeben und beenden. Wenn Sie, OTOH, immer noch fortfahren können (vielleicht eine andere Operation ausführen und hoffen, dass der Speicher später verfügbar wird), möchten Sie wahrscheinlich an diesem Speicher festhalten und einen anderen versuchen realloc später.

Kapitel und Vers:

7.22.3.5 Die realloc-Funktion

Zusammenfassung

1

     #include <stdlib.h>
     void *realloc(void *ptr, size_t size);

Beschreibung

2 Die realloc Funktion hebt das alte Objekt auf darauf hingewiesen von ptr und gibt einen Zeiger auf ein neues Objekt zurück, das die durch angegebene Größe hat size. Der Inhalt des neuen Objekts soll derselbe wie der des alten Objekts vor der Freigabe sein, bis auf die kleinere der neuen und alten Größen. Alle Bytes im neuen Objekt, die über die Größe des alten Objekts hinausgehen, haben unbestimmte Werte.

3 Wenn ptr ist ein Nullzeiger, der realloc Funktion verhält sich wie die malloc Funktion für die angegebene Größe. Ansonsten, wenn ptr 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 Funktion, das Verhalten ist undefiniert. Wenn kein Speicher für das neue Objekt zugewiesen werden kann, wird die Zuweisung des alten Objekts nicht aufgehoben und sein Wert bleibt unverändert.

Kehrt zurück

4 Die realloc Die Funktion gibt einen Zeiger auf das neue Objekt zurück (der den gleichen Wert wie ein Zeiger auf das alte Objekt haben kann) oder einen Nullzeiger, wenn das neue Objekt nicht zugewiesen werden konnte.

Betonung hinzugefügt. Beachten Sie Abschnitt 4; Der zurückgegebene Zeiger kann mit Ihrem ursprünglichen Zeiger identisch sein.

  • Der C11-Standardentwurf ist n1570.pdf, den Sie durch googeln finden können. Ich finde es hilfreich, mit Links zu zitieren (z Klicken Sie auf diesen Link bringt Sie zum realloc Abschnitt von n1570.html, der aus n1570.pdf konvertiert wurde).

    – autistisch

    2. Januar 2016 um 22:39 Uhr

1350210cookie-checkRichtige Verwendung von realloc()

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

Privacy policy