Ich habe über Diskussionen darüber gelesen, wie malloc
verhält sich, wenn Sie einen Block der Größe Null anfordern.
Ich verstehe, dass das Verhalten von malloc(0)
ist implementierungsdefiniert und soll entweder einen Nullzeiger zurückgeben, oder ein Nicht-Null-Zeiger, auf den ich trotzdem nicht zugreifen soll. (Was sinnvoll ist, da es keine Garantie dafür gibt, dass es auf einen verwendbaren Speicher verweist.)
Wenn ich jedoch einen solchen nicht zugänglichen Nicht-Null-Zeiger bekomme, darf ich ihn weitergeben free
auf die übliche Weise? Oder ist das illegal, da bekomme ich den Hinweis ab malloc(0)
möglicherweise nicht auf einen tatsächlich zugewiesenen Speicherblock?
Hat der folgende Code konkret ein wohldefiniertes Verhalten:
#include <stdio.h>
#include <stdlib.h>
int main() {
int* x = (int*) malloc(0);
if (x == NULL) {
printf("Got NULL\n");
return 0;
} else {
printf("Got nonnull %p\n", x);
}
free(x); // is calling `free` here okay?
}
Der C99-Standard (eigentlich WG14/N1124. Committee Draft – 6. Mai 2005. ISO/IEC 9899:TC2) sagt ungefähr malloc()
:
Der zurückgegebene Zeiger zeigt auf den Anfang (niedrigste Byte-Adresse) des zugewiesenen Speicherplatzes. Wenn der Speicherplatz nicht zugewiesen werden kann, wird ein Nullzeiger zurückgegeben. Wenn die Größe des angeforderten Speicherplatzes Null ist, ist das Verhalten implementierungsdefiniert: Entweder wird ein Nullzeiger zurückgegeben, oder das Verhalten ist so, als ob die Größe ein Wert ungleich Null wäre, außer dass der zurückgegebene Zeiger nicht verwendet werden soll, um auf ein Objekt zuzugreifen
und über free()
:
Andernfalls, wenn das Argument nicht mit einem Zeiger übereinstimmt, der zuvor von der Funktion calloc, malloc oder realloc zurückgegeben wurde, oder wenn der Speicherplatz durch einen Aufruf von free oder realloc freigegeben wurde, ist das Verhalten undefiniert.
IEEE Std 1003.1-2008 (POSIX), Ausgabe 2016 sagt ungefähr free()
:
Die Funktion free() soll bewirken, dass der Raum, auf den ptr zeigt, freigegeben wird; das heißt, zur weiteren Zuordnung verfügbar gemacht. Wenn ptr ein Nullzeiger ist, soll keine Aktion stattfinden. Andernfalls, wenn das Argument nicht mit einem Zeiger übereinstimmt, der zuvor von einer Funktion in POSIX.1-2008 zurückgegeben wurde, die Speicher wie durch malloc() zuweist, oder wenn der Speicherplatz durch einen Aufruf von free() oder realloc() freigegeben wurde, Das Verhalten ist undefiniert.
Was auch immer *alloc()
zurückkehrt, können Sie zu übergeben free()
.
Wie für die aktuellen Implementierungen von malloc()
:
FreeBSD verwendet das beigesteuerte jemalloc, das dies tut
void *
je_malloc(size_t size)
{
void *ret;
size_t usize JEMALLOC_CC_SILENCE_INIT(0);
if (size == 0)
size = 1;
[...]
Während Apples libmalloc dies tut
void *
szone_memalign(szone_t *szone, size_t alignment, size_t size)
{
if (size == 0) {
size = 1; // Ensures we'll return an aligned free()-able pointer
[...]
Der GLIBC ändert auch die angeforderte Größe; Es verwendet einen Aufruf dieses Makros mit der angeforderten Größe in Bytes als Parameter, um die Größe an einer bestimmten Grenze oder einfach an der minimalen Zuordnungsgröße auszurichten:
#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
Ja, in der Tat müssen Sie dies tun, um ein mögliches Speicherleck zu vermeiden.
Das malloc-System gibt normalerweise einen versteckten Steuerblock in dem Raum unmittelbar vor dem Zeiger zurück, mit Informationen wie der Zuordnungsgröße. Wenn die Zuweisungsgröße null ist, existiert dieser Block immer noch und belegt Speicher, wenn malloc nicht null zurückgibt.
Ja, du kannst
free
das Ergebnis vonmalloc
– MM
2. Juni 2017 um 14:26 Uhr
“Wenn size 0 ist, gibt malloc() entweder NULL oder einen eindeutigen Zeigerwert zurück, der später erfolgreich an free() übergeben werden kann.”, linux.die.net/man/3/mallocRTFM: p.
– Sternengatter
2. Juni 2017 um 14:27 Uhr
Sie werden auch garantiert bestehen können
NULL
zufree()
. Wie auch immermalloc()
Rücksendungen können sicher seinfree()
d (einmal).– Rici
2. Juni 2017 um 14:32 Uhr
@MM, nein, wirf überhaupt keine Zeiger. Verwenden Sie in Code wie diesem
void*
Anstatt vonint*
werfen Sie nicht das Ergebnis vonmalloc
wie auch immer, und verwenden Sie die%p
Bezeichner zum Drucken von Zeigern.– Jens Gustedt
2. Juni 2017 um 14:40 Uhr
@JensGustedt
%p
Das Format ist nicht definiert, ob es hexadezimal oder dezimal ist, wie die Formatierung ist … es gibt Gründe, Zeiger zum Drucken in Ganzzahlen umzuwandeln, um das Ausgabeformat zu steuern– MM
2. Juni 2017 um 14:43 Uhr