Ich habe darüber gelesen realloc
und war verwirrt über einen dort erwähnten Punkt. Betrachten Sie den folgenden Code:
#include <stdio.h>
#include <stdlib.h>
int main () {
int* ptr = NULL;
ptr = realloc(ptr, 10*sizeof(int));
return 0;
}
Besteht eine Gefahr bei der Speicherzuweisung mit realloc
mit dem anfangs NULL
-geschätzt ptr
? Wenn statt:
int* ptr = NULL;
Ich hatte das:
int* ptr; // no value given to ptr
Wäre es ein Problem anzurufen realloc
verwenden ptr
?
Besteht eine Gefahr bei der Zuweisung von Speicher mit realloc unter Verwendung des anfänglich NULL-wertigen ptr
Keiner
7.22.3.5
Wenn ptr ein Nullzeiger ist, verhält sich die Funktion realloc für die angegebene Größe wie die Funktion malloc.
Zum zweiten Teil:
int* ptr; // no value given to ptr
Wäre es ein Problem, realloc mit ptr aufzurufen?
Wenn Sie nicht initialisierte Zeiger verwenden, ist dies in der Tat ein sehr ernstes Problem, da Sie nicht vorhersagen können, welchen Wert sie haben werden. Die Funktion realloc
funktioniert nur korrekt für NULL
oder Werte erhalten aus malloc
/ realloc
.
Andernfalls, wenn ptr nicht mit einem Zeiger übereinstimmt, der zuvor von einer Speicherverwaltungsfunktion zurückgegeben wurde […] das Verhalten ist undefiniert
Mit dem gezeigten spezifischen Code gibt es kein Problem mit der anfänglichen Verwendung des Nullzeigers.
Wenn die Variable ptr
nicht initialisiert ist – nicht auf 0 oder NULL gesetzt – dann ist jeder Aufruf an realloc()
seine Verwendung ist gefährlich; Das Verhalten ist undefiniert und wenn Sie Glück haben, stürzt das Programm ab, aber wenn Sie Pech haben, scheint es eine Weile zu funktionieren, bis später im Programm etwas schief geht, wo es schwierig sein wird, das Problem zu erkennen in Code, der vor langer Zeit ausgeführt wurde.
Es gibt diejenigen, die argumentieren, dass es besser ist, es zu verwenden malloc()
für die Erstzuteilung und realloc()
danach. Der Vorschlag ist einigermaßen gerechtfertigt, nicht zuletzt, weil Sie ihn wahrscheinlich nicht verwenden würden ptr = realloc(ptr, 0);
um den Speicher freizugeben, obwohl Sie dies tun könnten (also brauchen Sie es nicht wirklich malloc()
oder free()
Weil realloc()
kann alle drei Operationen ausführen). Aber der C90-Standard erfordert realloc(0, new_size)
gleichwertig zu arbeiten malloc(new_size)
und ich kenne keine C-Bibliothek, die sich anders verhält (aber es könnte einige geben; ich habe nur wenige C-Bibliotheken verwendet, wenn auch meistens die am weitesten verbreiteten).
In einem allgemeineren Fall wie dem folgenden Code gibt es jedoch ein subtiles Problem mit dem Code (aber es hat nichts mit dem anfänglichen Nullzeiger zu tun):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
if ((ptr = realloc(ptr, buflen)) == 0) // Danger!
// ... handle memory allocation failure ...
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
Was ist die Gefahr? Die Gefahr besteht darin, dass, wenn die zweite oder eine nachfolgende Speicherzuweisung fehlschlägt und ptr
der einzige Zeiger auf den zugewiesenen Speicher ist, überschreiben Sie einfach seinen vorherigen Wert mit null. Das bedeutet, dass Sie den zugewiesenen Speicher nicht mit freigeben können ptr
nicht mehr – Sie haben Speicher durchgesickert. (Bei der ersten Zuweisung war der Anfangswert 0, der überschriebene Wert war 0, und es hat sich nichts geändert; es gibt kein Speicherleck. Deshalb wurde die Schleife zum Code hinzugefügt.)
Faustregel
- Schreibe nicht
ptr = realloc(ptr, newsize);
Speichern Sie den neuen Wert in einer separaten Variablen, bis Sie ihn getestet haben.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
char *new_ptr = realloc(ptr, buflen);
if (new_ptr == 0)
// ... handle memory allocation failure ...
ptr = new_ptr;
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
Dieser Code verliert bei einem Zuordnungsfehler keinen Speicher.
Hilfsempfehlung: Verwenden Sie keine Variable namens new
; es wird es schwierig machen, mit einem C++-Compiler zu kompilieren. Selbst wenn Sie jetzt nicht die Absicht haben, nach C++ zu konvertieren (und obwohl Sie wahrscheinlich die Speicherverwaltung neu schreiben würden, wenn Sie dies tun würden), ist die Verwendung des Schlüsselworts C++ nicht zielführend new
als C-Variablenname … es sei denn, Sie möchten explizit die Kompilierung mit einem C++-Compiler verhindern.
Besteht eine Gefahr bei der Zuweisung von Speicher mit realloc unter Verwendung des anfänglich NULL-wertigen ptr?
Nein, das wäre genau wie ein malloc
.
Wenn statt:
int* ptr = NULL;
Ich hatte das:
int* ptr; // no value given to ptr
Wäre es ein Problem, realloc mit ptr aufzurufen?
Ja, es gäbe ein Problem. Wenn realloc
bekommt kein NULL
es wird versuchen, den Speicher ab diesem Ort zu erweitern, oder kann versuchen zu free
und malloc
ein weiterer Teil der Erinnerung. Seit Nicht initialisierte Variablen können jeden Wert habenChancen sind sehr hoch, sie sind kein Wert realloc
Likes. Wenn Sie Glück haben, würde Ihr Programm sofort abstürzen.
ptr = realloc(ptr, 10*sizeof(int));
Wenn realloc fehlschlägt, verlieren Sie Speicher.– Ayxan Haqverdili
10. Januar 2020 um 4:28 Uhr
@AyxanHaqverdili, aber in diesem Fall kann kein Speicher verloren gehen.
– Kaihaku
20. September 2021 um 6:07 Uhr
@Kaihaku Ich habe wahrscheinlich über den allgemeinen Fall gesprochen.
– Ayxan Haqverdili
20. September 2021 um 6:13 Uhr