Jiní odpověděli jak malloc(0)
funguje. Odpovím na jednu z vašich otázek, která ještě nebyla zodpovězena (myslím). Otázka se týká realloc(malloc(0), 0)
:
Co znamená
malloc(0)
vrátit se? Byla by odpověď stejná prorealloc(malloc(0),0)
?
Norma říká toto o realloc(ptr, size)
:
- pokud
ptr
jeNULL
, chová se jakomalloc(size)
, - jinak (
ptr
neníNULL
), uvolní starý ukazatel objektu naptr
a vrátí ukazatel na novou přidělenou vyrovnávací paměť. Ale pokudsize
je 0, C89 říká, že efekt je ekvivalentnífree(ptr)
. Zajímavé je, že toto prohlášení nemohu najít v návrhu C99 (n1256 nebo n1336). V C89 by jediná rozumná hodnota, která by se v tomto případě vrátila, bylaNULL
.
Takže existují dva případy:
malloc(0)
vrátíNULL
na implementaci. Potom vašerealloc()
volání je ekvivalentnírealloc(NULL, 0)
. To je ekvivalentnímalloc(0)
shora (a to jeNULL
v tomto případě).malloc(0)
vrátí non-NULL
. Potom je volání ekvivalentnífree(malloc(0))
. V tomto případěmalloc(0)
arealloc(malloc(0), 0)
nejsou ekvivalentní.
Všimněte si, že zde je zajímavý případ:ve druhém případě, kdy malloc(0)
vrátí non-NULL
v případě úspěchu může stále vrátit NULL
indikovat selhání. Výsledkem bude volání jako:realloc(NULL, 0)
, což by bylo ekvivalentní malloc(0)
, který může nebo nemusí vrátit NULL
.
Nejsem si jistý, zda je vynechání v C99 nedopatřením, nebo to znamená, že v C99 realloc(ptr, 0)
pro jiné než NULL
ptr
není ekvivalentní free(ptr)
. Právě jsem to zkusil s gcc -std=c99
a výše uvedené je ekvivalentní free(ptr)
.
Upravit :Myslím, že chápu, v čem je váš zmatek:
Podívejme se na úryvek z vašeho příkladu kódu:
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
Výše uvedené není totéž jako malloc(0) == realloc(malloc(0), 1024)
. Ve druhém malloc()
volání je provedeno dvakrát, zatímco v prvním předáváte dříve přidělený ukazatel na realloc()
.
Nejprve analyzujeme první kód. Za předpokladu malloc(0)
nevrací NULL
v případě úspěchu ptr
má platnou hodnotu. Když uděláte realloc(ptr, 1024)
, realloc()
v podstatě vám dává nový buffer, který má velikost 1024 a ptr
stane neplatným. Vyhovující implementace může vrátit stejnou adresu, jako je ta již v ptr
. Takže vaše if
podmínka se může vrátit jako true. (Všimněte si však hodnoty ptr
po realloc(ptr, 1024)
může být nedefinované chování.)
Nyní otázka, kterou si kladete:malloc(0) == realloc(malloc(0), 1024)
. V tomto případě předpokládejme, že obě malloc(0)
na LHS a RHS vrací non-NULL
. Pak je zaručeno, že se budou lišit. Také vrácená hodnota z malloc()
na LHS nebyl free()
d ještě, takže jakýkoli jiný malloc()
, calloc()
nebo realloc()
nemusí tuto hodnotu vrátit. To znamená, že pokud jste svou podmínku napsali jako:
if (malloc(0) == realloc(malloc(0), 1024)
puts("possible");
neuvidíte possible
na výstupu (pokud oba malloc()
a realloc()
selže a vrátí NULL
).
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *p1;
void *p2;
p1 = malloc(0);
p2 = realloc(p1, 1024);
if (p1 == p2)
puts("possible, OK");
/* Ignore the memory leaks */
if (malloc(0) == realloc(malloc(0), 1024))
puts("shouldn't happen, something is wrong");
return 0;
}
V OS X můj kód při spuštění nic nevypisoval. V systému Linux tiskne possible, OK
.
malloc(0)
je Implementace definována pokud jde o C99.
Od C99 [Oddíl 7.20.3]
Pořadí a spojitost úložiště přiděleného postupnými voláními funkcí calloc, malloc a realloc není specifikováno . Ukazatel vrácený, pokud je alokace úspěšná, je vhodně zarovnán tak, aby mohl být přiřazen k ukazateli na jakýkoli typ objektu a poté použit pro přístup k takovému objektu nebo poli takových objektů v přiděleném prostoru (dokud není prostor explicitně uvolněn). Životnost alokovaného objektu se prodlužuje od alokace do dealokace. Každé takové přidělení poskytne ukazatel na objekt disjunktní od jakéhokoli jiného objektu. Ukazatel vrátil body na začátek (nejnižší byteaddress) přiděleného prostoru. Pokud prostor nelze přidělit, je vrácen nulový ukazatel. Pokud je velikost požadovaného prostoru nula, je chování definováno implementací :buď je vrácen nulový ukazatel, nebo se chová, jako by velikost byla nějaká nenulová hodnota, kromě toho, že vrácený ukazatel nebude použit pro přístup k objektu.
V C89 je malloc(0) závislý na implementaci - nevím, jestli to C99 opravil nebo ne. V C++ pomocí:
char * p = new char[0];
je dobře definován – získáte platný, nenulový ukazatel. Samozřejmě nemůžete použít ukazatel pro přístup k tomu, na co ukazuje, aniž byste vyvolali nedefinované chování.
Pokud jde o to, proč to existuje, je to vhodné pro některé algoritmy a znamená to, že nemusíte zasypávat kód testy na nulové hodnoty.