Ich habe gerade diesen Code gesehen:
artist = (char *) malloc(0);
... und ich fragte mich, warum man das tun sollte?
Ich habe gerade diesen Code gesehen:
artist = (char *) malloc(0);
... und ich fragte mich, warum man das tun sollte?
Antworten:
Gemäß den Spezifikationen gibt malloc (0) entweder "einen Nullzeiger oder einen eindeutigen Zeiger zurück, der erfolgreich an free () übergeben werden kann".
Auf diese Weise können Sie im Grunde nichts zuweisen, aber die Variable "artist" ohne Bedenken an einen Aufruf von free () übergeben. Aus praktischen Gründen ist es so ziemlich das Gleiche wie:
artist = NULL;
Der C-Standard (C17 7.22.3 / 1) lautet:
Wenn die Größe des angeforderten Speicherplatzes Null ist, wird das Verhalten durch die Implementierung definiert: Entweder wird ein Nullzeiger zurückgegeben, oder das Verhalten ist so, als ob die Größe ein Wert ungleich Null wäre, mit der Ausnahme, dass der zurückgegebene Zeiger nicht für den Zugriff auf ein Objekt verwendet werden soll.
So malloc(0)
könnte zurückkehren NULL
oder ein gültiger Zeiger , die nicht dereferenziert werden kann . In beiden Fällen ist es durchaus gültig, free()
darauf zurückzugreifen.
Ich denke nicht, dass malloc(0)
es viel Sinn macht, außer in Fällen, in denen malloc(n)
es zum Beispiel in einer Schleife aufgerufen wird und n
möglicherweise Null ist.
Wenn ich mir den Code im Link anschaue, glaube ich, dass der Autor zwei falsche Vorstellungen hatte:
malloc(0)
gibt einen gültigen Zeiger immer , undfree(0)
ist schlecht.Also stellte er sicher, dass diese artist
und andere Variablen immer einen "gültigen" Wert hatten. Der Kommentar sagt so viel : // these must always point at malloc'd data
.
malloc(0)
ein gültiger Zeiger malloc()
zurückgegeben wird, NULL
bedeutet die Rückgabe immer "Fehler" und 0
ist kein Sonderfall mehr, der konsistenter ist.
malloc
, unter denen kein Speicher abgerufen werden kann, implementierungsdefiniert sind, könnte eine Implementierung einfach definieren, dass Zuweisungen der Größe 0 immer unbefriedigend sind ( ENOMEM
), und jetzt ist die malloc(0)
Rückgabe von 0 (mit errno==ENOMEM
) konsistent. :-)
realloc
einen Zeiger von zurückgeben malloc(0)
? Können Sie realloc((char*)NULL)
?
Das Verhalten von malloc (0) ist implementierungsspezifisch. Die Bibliothek kann NULL zurückgeben oder das normale Malloc-Verhalten aufweisen, ohne dass Speicher zugewiesen ist. Was auch immer es tut, es muss irgendwo dokumentiert werden.
Normalerweise wird ein Zeiger zurückgegeben, der gültig und eindeutig ist, aber NICHT dereferenziert werden sollte. Beachten Sie auch, dass es Speicher verbrauchen kann, obwohl es eigentlich nichts zugewiesen hat.
Es ist möglich, einen Malloc (0) -Zeiger ungleich Null neu zuzuweisen.
Ein Malloc (0) wörtlich zu haben, ist jedoch nicht sehr nützlich. Es wird meistens verwendet, wenn eine dynamische Zuordnung null Byte beträgt und Sie sie nicht validieren wollten.
malloc()
muss irgendwo "Housekeeping-Informationen" aufbewahren (diese Größe des zugewiesenen Blocks zum Beispiel und andere Hilfsdaten). Wenn malloc(0)
dies nicht der Fall ist NULL
, wird der Speicher zum Speichern dieser Informationen verwendet, und wenn nicht free()
, wird d einen Speicherverlust darstellen.
malloc()
wird, oder zurückgeben NULL
.
malloc(0)
. In derselben Implementierung der Standard-C-Bibliothek wird jedoch NULL realloc(ptr, 0)
freigegeben ptr
und zurückgegeben.
An anderer Stelle auf dieser Seite gibt es eine Antwort, die beginnt: "malloc (0) gibt eine gültige Speicheradresse zurück und deren Bereich hängt von der Art des Zeigers ab, dem Speicher zugewiesen wird." Diese Aussage ist falsch (ich habe nicht genug Ruf, um diese Antwort direkt zu kommentieren, kann diesen Kommentar also nicht direkt darunter platzieren).
Wenn Sie malloc (0) ausführen, wird nicht automatisch Speicher mit der richtigen Größe zugewiesen. Die Malloc-Funktion weiß nicht, auf was Sie das Ergebnis übertragen. Die Malloc-Funktion basiert ausschließlich auf der Größenzahl, die Sie als Argument angeben. Sie müssen malloc (sizeof (int)) ausführen, um genügend Speicherplatz für ein int zu erhalten, z. B. nicht 0.
malloc(0)
macht für mich keinen Sinn, es sei denn, der Code basiert auf einem für die Implementierung spezifischen Verhalten. Wenn der Code portabel sein soll, muss er die Tatsache berücksichtigen, dass eine NULL-Rückgabe von malloc(0)
kein Fehler ist. Warum also nicht einfach NULL zuweisen artist
, da dies ein gültiges erfolgreiches Ergebnis ist und weniger Code enthält und Ihre Wartungsprogrammierer sich nicht die Zeit nehmen müssen, es herauszufinden?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
oder malloc(some_variable_which_might_be_zero)
vielleicht könnten sie ihre Verwendung haben, obwohl Sie wiederum besonders darauf achten müssen, eine NULL-Rückgabe nicht als Fehler zu behandeln, wenn der Wert 0 ist, aber eine 0-Größe in Ordnung sein soll.
Hier gibt es viele halbwahre Antworten, also hier die harten Fakten. Die Manpage für malloc()
sagt:
Wenn die Größe 0 ist, gibt malloc () entweder NULL oder einen eindeutigen Zeigerwert zurück, der später erfolgreich an free () übergeben werden kann.
Das heißt, es gibt absolut keine Garantie dafür, dass das Ergebnis von malloc(0)
entweder eindeutig oder nicht NULL ist. Die einzige Garantie besteht in der Definition von free()
: Hier ist, was auf der Manpage steht:
Wenn ptr NULL ist, wird keine Operation ausgeführt.
Was auch immer malloc(0)
zurückkommt, es kann sicher weitergegeben werden free()
. Aber auch ein NULL
Zeiger.
Folglich ist Schreiben artist = malloc(0);
in keiner Weise besser als Schreiben artist = NULL;
malloc(0)
könnte beispielsweise 0x1 zurückgegeben werden, und es free()
könnte eine Sonderfallprüfung von 0x1 durchgeführt werden, genau wie bei 0x0.
NULL
oder ein eindeutiger Zeiger" sein muss. stattdessen 'entweder ein Nullzeiger oder ein Zeiger auf den zugewiesenen Speicherplatz ". Es gibt keine eindeutige Anforderung. OTOH, die Rückgabe eines nicht eindeutigen Sonderwerts kann den Code stören, der auf eindeutigen Werten zählt. Vielleicht eine
man
kann auch die in * nix verwendete implementierungsdefinierte Form dokumentieren. In diesem Fall nicht, aber es ist immer noch keine kanonische Quelle für General C.
Warum sollten Sie das nicht tun ...
Da der Rückgabewert von malloc implementierungsabhängig ist, erhalten Sie möglicherweise einen NULL-Zeiger oder eine andere Adresse zurück. Dies kann zu Heap-Buffer-Überläufen führen, wenn der Fehlerbehandlungscode nicht sowohl die Größe als auch den zurückgegebenen Wert überprüft, was zu Stabilitätsproblemen (Abstürzen) oder noch schlimmeren Sicherheitsproblemen führt.
Betrachten Sie dieses Beispiel, in dem ein weiterer Zugriff auf den Speicher über die zurückgegebene Adresse den Heap beschädigt, wenn die Größe Null ist und die Implementierung einen Nicht-NULL-Wert zurückgibt.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
Siehe diese Seite zur sicheren Codierung aus den CERT-Codierungsstandards, auf der ich das obige Beispiel zur weiteren Lektüre verwendet habe.
Zugegeben, ich habe das noch nie gesehen, dies ist das erste Mal, dass ich diese Syntax gesehen habe, man könnte sagen, ein klassischer Fall von Funktionsüberschuss. In Verbindung mit Reeds Antwort möchte ich darauf hinweisen, dass es eine ähnliche Sache gibt, die wie eine überladene Funktion erscheint realloc
:
realloc(foo, size);
. Wenn Sie einen Nicht-NULL-Zeiger und eine Größe von Null an realloc übergeben, verhält sich realloc so, als hätten Sie free (…) aufgerufen.realloc(foo, size);
. Wenn Sie einen NULL-Zeiger übergeben und die Größe ungleich Null ist, verhält sich Realloc so, als hätten Sie malloc (…) aufgerufen.Hoffe das hilft, Mit freundlichen Grüßen, Tom.
malloc (0) gibt NULL oder einen gültigen Zeiger zurück, der zu Recht an free übergeben werden kann. Und obwohl es so aussieht, als ob die Erinnerung, auf die es zeigt, nutzlos ist oder nicht beschrieben oder gelesen werden kann, ist dies nicht immer der Fall. :) :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
Wir erwarten hier einen Segmentierungsfehler, aber überraschenderweise werden 100 gedruckt! Das liegt daran, dass malloc tatsächlich nach einem großen Speicherplatz fragt, wenn wir malloc zum ersten Mal anrufen. Bei jedem weiteren Aufruf von malloc wird der Speicher dieses großen Teils verwendet. Erst nachdem dieser riesige Teil vorbei ist, wird nach neuem Speicher gefragt.
Verwendung von malloc (0): Wenn Sie sich in einer Situation befinden, in der nachfolgende malloc-Aufrufe schneller ausgeführt werden sollen, sollte der Aufruf von malloc (0) dies für Sie tun (mit Ausnahme von Randfällen).
*i
stürzt in Ihrem Fall möglicherweise nicht ab, ist aber dennoch ein undefiniertes Verhalten. Achten Sie auf Nasendämonen!
malloc(0)
, die nicht erwähnt wird. Bei Implementierungen, bei denen ein Wert ungleich NULL zurückgegeben wird, insbesondere in einem DEBUG-Build, wird wahrscheinlich MEHR zugewiesen, als Sie angefordert haben, und Sie erhalten den Zeiger auf knapp hinter dem internen Header. Auf diese Weise erhalten Sie ein Gefühl für die tatsächliche Speichernutzung, wenn Sie diese vor und nach einer Reihe von Zuweisungen erhalten. zB: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
oder so.
malloc(0)
. Könnten Sie bitte sagen, auf welches Kapitel Sie sich auch beziehen? Ein genaues Angebot zu machen wäre auch schön.
In Windows:
void *p = malloc(0);
weist dem lokalen Heap einen Puffer mit der Länge Null zu. Der zurückgegebene Zeiger ist ein gültiger Heap-Zeiger.malloc
ruft letztendlich HeapAlloc
mit dem Standard-C-Laufzeitheap auf, der dann RtlAllocateHeap
usw. aufruft .free(p);
wird verwendet HeapFree
, um den Puffer mit der Länge 0 auf dem Heap freizugeben. Wenn es nicht freigegeben wird, führt dies zu einem Speicherverlust.Es ist eigentlich ziemlich nützlich und (offensichtlich IMHO) das erlaubte Verhalten, einen NULL-Zeiger zurückzugeben, ist gebrochen. Ein dynamischer Zeiger ist nicht nur nützlich für das, worauf er zeigt, sondern auch für die Tatsache, dass seine Adresse eindeutig ist. Wenn Sie NULL zurückgeben, wird diese zweite Eigenschaft entfernt. Alle eingebetteten Mallocs, die ich programmiere (tatsächlich ziemlich häufig), haben dieses Verhalten.
Ich bin mir nicht sicher, ob eine Eingabe von 0 laut einem zufälligen Malloc-Quellcode , den ich gefunden habe, zu einem Rückgabewert von NULL führt. Es ist also eine verrückte Art, den Künstlerzeiger auf NULL zu setzen.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Hier ist die Analyse nach dem Ausführen mit dem Valgrind Memory Check Tool.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
und hier ist mein Beispielcode:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
Standardmäßig werden 1024 Bytes zugewiesen. Wenn ich malloc vergrößere, erhöhen sich die zugewiesenen Bytes um 1025 und so weiter.
Laut der Antwort von Reed Copsey und der Manpage von malloc habe ich einige Beispiele zum Testen geschrieben. Und ich habe herausgefunden, dass malloc (0) ihm immer einen eindeutigen Wert geben wird. Siehe mein Beispiel:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
Die Ausgabe ptr
lautet "Habe einen gültigen Zeiger", was bedeutet, dass er nicht null ist.
malloc(0)
gibt eine gültige Speicheradresse zurück und deren Bereich hängt von der Art des Zeigers ab, dem Speicher zugewiesen wird. Sie können dem Speicherbereich auch Werte zuweisen, dies sollte jedoch im Bereich des verwendeten Zeigertyps liegen. Sie können auch den zugewiesenen Speicher freigeben. Ich werde dies anhand eines Beispiels erklären:
int *p=NULL;
p=(int *)malloc(0);
free(p);
Der obige Code funktioniert in einem gcc
Compiler auf einem Linux-Computer einwandfrei. Wenn Sie einen 32-Bit-Compiler haben, können Sie Werte im ganzzahligen Bereich angeben, dh -2147483648 bis 2147483647. Gleiches gilt auch für Zeichen. Bitte beachten Sie, dass , wenn der Typ des Visiers wird dann den Wertebereich geändert erklärt werden , unabhängig von ändern malloc
Typumwandlung, dh
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
nimmt einen Wert von 0 bis 255 von char an, da es als vorzeichenloses int deklariert ist.
malloc()
weiß nichts über die Besetzung (die in C eigentlich völlig überflüssig ist). Das Dereferenzieren des Rückgabewerts von malloc(0)
führt zu undefiniertem Verhalten.
Nur um hier einen falschen Eindruck zu korrigieren:
artist = (char *) malloc(0);
wird niemals zurückkehren NULL
; es ist nicht dasselbe wie artist = NULL;
. Schreiben Sie ein einfaches Programm und vergleichen Sie artist
mit NULL
. if (artist == NULL)
ist falsch und if (artist)
ist wahr.