Was ist der Sinn von Malloc (0)?


Antworten:


121

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;

51
Persönlich denke ich, dass die Einstellung auf NULL eine bessere plattformübergreifende Strategie ist, da free () (gemäß Spezifikation) garantiert einwandfrei mit NULL als Eingabe funktioniert.
Reed Copsey

2
Wie von C. Ross erwähnt, könnten einige Plattformen hier technisch gesehen einen Zeiger zurückgeben (dies ist ein "eindeutiger Zeiger, der an free übergeben werden kann"). Wenn Sie dies jedoch als Zeichen * behandeln, erhalten Sie möglicherweise einen ungültiges, nicht terminiertes Zeichen In plattformübergreifenden Situationen kann es gefährlich sein, sich darauf zu verlassen.
Reed Copsey

9
Ich wünschte wirklich, die Spezifikationen würden auch "sicher an realloc übergeben" sagen
-.-

1
@NSAddict "leere Struktur, in der sizeof 0 zurückgibt", geben Sie ein Beispiel an, das sich wie eine Spracherweiterung anhört.
chux

1
@ Hanshenrik Wer sagt, dass du nicht kannst? realloc()Ermöglicht die Übergabe eines gültigen Zeigers, der von zurückgegeben wird malloc(). Sollte genug sein.
glglgl

51

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 NULLoder 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 nmö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 , und
  • free(0) ist schlecht.

Also stellte er sicher, dass diese artistund andere Variablen immer einen "gültigen" Wert hatten. Der Kommentar sagt so viel : // these must always point at malloc'd data.


10
Die Tatsache, dass es implementierungsabhängig ist, macht es mehr oder weniger völlig nutzlos - dies ist eines der schäbigsten Teile des C-Standards, und einige der Standardausschüsse (zum Beispiel PJ Plauger) haben darüber gestöhnt.

10
Genau. Wenn malloc(0)ein gültiger Zeiger malloc()zurückgegeben wird, NULLbedeutet die Rückgabe immer "Fehler" und 0ist kein Sonderfall mehr, der konsistenter ist.
Alok Singhal

1
Da die Umstände 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. :-)
R .. GitHub STOP HELPING ICE

6
Können Sie realloceinen Zeiger von zurückgeben malloc(0)? Können Sie realloc((char*)NULL)?
Braden Best

3
@Braden Best Ja zu beiden.
chux

11

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.


9
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.
Alok Singhal

Malloc-Implementierungen führen Aufzeichnungen durch, bei denen eine bestimmte Datenmenge pro zurückgegebenem Zeiger zusätzlich zur angeforderten Größe hinzugefügt werden kann.
user7116

1
Der verbrauchte und der zugewiesene Speicher bedeuten nicht dasselbe. In diesem Fall geben die meisten Implementierungen einen eindeutigen Zeiger zurück. Dies bedeutet, dass ein Teil des Adressraums für diesen Zeiger geopfert werden muss. Abhängig vom Allokator kann dies tatsächlich bedeuten, dass 1 Byte oder mehr zugewiesen wird.
Coincoin

1
Die Bibliothek kann tun, was sie will - nun, sie kann entweder einen eindeutigen Zeiger zurückgeben, den kein anderer zurückgeben malloc()wird, oder zurückgeben NULL.
Alok Singhal

1
@jldupont: Zumindest die Microsoft C-Laufzeitbibliothek gibt einen eindeutigen Zeiger für zurück malloc(0). In derselben Implementierung der Standard-C-Bibliothek wird jedoch NULL realloc(ptr, 0)freigegeben ptrund zurückgegeben.
Medinoc

5

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.


4

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.


3

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 NULLZeiger.

Folglich ist Schreiben artist = malloc(0); in keiner Weise besser als Schreiben artist = NULL;


1
Schade, dass die Implementierung keinen nicht null, nicht eindeutigen Zeiger zurückgeben darf. Auf diese Weise 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.
Todd Lehman

3
@Todd Lehman Eine Implementierung kann das tun, was Sie vorschlagen. Die C-Spezifikation gibt nicht an, dass das Ergebnis " NULLoder 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
Eckfallfrage

mankann auch die in * nix verwendete implementierungsdefinierte Form dokumentieren. In diesem Fall nicht, aber es ist immer noch keine kanonische Quelle für General C.
Lundin

@ Lundin True. Die Manpages sind jedoch viel zugänglicher als der C-Standard, und die Manpages auf GNU / Linux-Systemen dokumentieren im Allgemeinen recht gut, welchen Standards die Implementierung folgt. Zusammen mit Informationen darüber, welche Teile welcher Norm entsprechen, sollten sie sich unterscheiden. Ich habe das Gefühl, dass beide präzise sein wollen und für jedes einzelne Bit werben wollen, das eine GNU-Erweiterung ist ...
cmaster -

3

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.



2

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:

  • foo ist nicht NULL und die Größe ist Null 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.
  • foo ist NULL und die Größe ist ungleich Null und größer als 1 , 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.


1

Um die gestellte Frage tatsächlich zu beantworten: Es gibt keinen Grund, dies zu tun


0

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).


1
Das Schreiben an *istürzt in Ihrem Fall möglicherweise nicht ab, ist aber dennoch ein undefiniertes Verhalten. Achten Sie auf Nasendämonen!
John Dvorak

1
Ja. Das ist wahr. Es ist implementierungsspezifisch. Ich habe es unter MaxOS X und einigen Linux-Distributionen überprüft. Ich habe es nicht auf anderen Plattformen versucht. Trotzdem wurde das von mir beschriebene Konzept in dem Buch "The C Programming Language" von Brain Kernighan und Dennis Ritchie beschrieben.
Sagar Bhosale

Ich weiß: super später Kommentar zu dieser Frage. Aber es gibt manchmal eine Verwendung dafür 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.
Jesse Chisholm

Ich habe "The C Programming Language" von Brain Kernighan und Dennis Ritchie gelesen und erinnere mich nicht daran, dass ich etwas darüber gesagt habe malloc(0). Könnten Sie bitte sagen, auf welches Kapitel Sie sich auch beziehen? Ein genaues Angebot zu machen wäre auch schön.
15ндрей Беньковский

0

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.
  • mallocruft letztendlich HeapAllocmit dem Standard-C-Laufzeitheap auf, der dann RtlAllocateHeapusw. 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.

0

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.



-2

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.


-3

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 ptrlautet "Habe einen gültigen Zeiger", was bedeutet, dass er nicht null ist.


-6

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 gccCompiler 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 mallocTypumwandlung, 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.


5
Krellan weist zu Recht darauf hin, dass diese Antwort falsch ist: Er 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.
cmaster

-6

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 artistmit NULL. if (artist == NULL)ist falsch und if (artist)ist wahr.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.