D'autres ont répondu comment malloc(0)
œuvres. Je vais répondre à l'une des questions que vous avez posées et qui n'a pas encore reçu de réponse (je pense). La question porte sur realloc(malloc(0), 0)
:
Que signifie
malloc(0)
revenir? La réponse serait-elle la même pourrealloc(malloc(0),0)
?
La norme dit ceci à propos de realloc(ptr, size)
:
- si
ptr
estNULL
, il se comporte commemalloc(size)
, - sinon (
ptr
n'est pasNULL
), il libère l'ancien pointeur d'objet deptr
et renvoie un pointeur vers un nouveau tampon alloué. Mais sisize
est 0, C89 indique que l'effet est équivalent àfree(ptr)
. Fait intéressant, je ne trouve pas cette déclaration dans le brouillon C99 (n1256 ou n1336). En C89, la seule valeur raisonnable à renvoyer dans ce cas seraitNULL
.
Donc, il y a deux cas :
malloc(0)
renvoieNULL
sur une implémentation. Puis votrerealloc()
call est équivalent àrealloc(NULL, 0)
. Cela équivaut àmalloc(0)
d'en haut (et c'estNULL
dans ce cas).malloc(0)
renvoie non-NULL
. Ensuite, l'appel est équivalent àfree(malloc(0))
. Dans ce cas,malloc(0)
etrealloc(malloc(0), 0)
ne sont pas équivalent.
Notez qu'il y a ici un cas intéressant :dans le second cas, quand malloc(0)
renvoie non-NULL
en cas de succès, il peut toujours renvoyer NULL
pour indiquer un échec. Cela se traduira par un appel comme :realloc(NULL, 0)
, ce qui équivaudrait à malloc(0)
, qui peut ou non renvoyer NULL
.
Je ne sais pas si l'omission dans C99 est un oubli ou si cela signifie que dans C99, realloc(ptr, 0)
pour non-NULL
ptr
n'est pas équivalent à free(ptr)
. Je viens d'essayer avec gcc -std=c99
, et ce qui précède est équivalent à free(ptr)
.
Modifier :Je pense que je comprends votre confusion :
Regardons un extrait de votre exemple de code :
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
Ce qui précède n'est pas le même que malloc(0) == realloc(malloc(0), 1024)
. Dans le second, le malloc()
l'appel est effectué deux fois, alors que dans le premier, vous passez un pointeur précédemment alloué à realloc()
.
Analysons d'abord le premier code. En supposant malloc(0)
ne renvoie pas NULL
en cas de succès, ptr
a une valeur valide. Lorsque vous faites realloc(ptr, 1024)
, realloc()
vous donne essentiellement un nouveau tampon qui a la taille 1024, et le ptr
devient invalide. Une implémentation conforme peut retourner la même adresse que celle déjà dans ptr
. Donc, votre if
condition peut retourner vrai. (Notez, cependant, en regardant la valeur de ptr
après realloc(ptr, 1024)
peut être un comportement indéfini.)
Maintenant la question que vous posez :malloc(0) == realloc(malloc(0), 1024)
. Dans ce cas, supposons que le malloc(0)
sur les retours LHS et RHS non NULL
. Ensuite, ils sont garantis différents. Aussi, la valeur de retour de malloc()
sur le LHS n'a pas été free()
d encore, donc tout autre malloc()
, calloc()
, ou realloc()
peut ne pas renvoyer cette valeur. Cela signifie que si vous avez écrit votre condition comme :
if (malloc(0) == realloc(malloc(0), 1024)
puts("possible");
vous ne verrez pas possible
sur la sortie (sauf si malloc()
et realloc()
échoue et renvoie 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;
}
Sous OS X, mon code n'a rien produit lorsque je l'ai exécuté. Sous Linux, il imprime possible, OK
.
malloc(0)
est défini par la mise en œuvre en ce qui concerne C99.
À partir de C99 [Section 7.20.3]
L'ordre et la contiguïté du stockage alloué par les appels successifs aux fonctions calloc, malloc et realloc ne sont pas spécifiés . Le pointeur renvoyé si l'allocation réussit est correctement aligné de sorte qu'il puisse être assigné à un pointeur vers n'importe quel type d'objet, puis utilisé pour accéder à un tel objet ou à un tableau de tels objets dans l'espace alloué (jusqu'à ce que l'espace soit explicitement désalloué). La durée de vie d'un objet alloué s'étend de l'allocation jusqu'à la désallocation. Chacune de ces allocations doit produire un pointeur vers un objet disjoint de tout autre objet. Le pointeur renvoyé pointe sur le début (adresse d'octet la plus basse) de l'espace alloué. Si l'espace ne peut pas être alloué, un pointeur nul est renvoyé. Si la taille de l'espace demandé est zéro, le comportement est défini par l'implémentation :soit un pointeur nul est renvoyé, soit le comportement est comme si la taille était une valeur différente de zéro, sauf que le pointeur renvoyé ne doit pas être utilisé pour accéder à un objet.
Dans C89, malloc(0) dépend de l'implémentation - je ne sais pas si C99 a corrigé cela ou non. En C++, en utilisant :
char * p = new char[0];
est bien défini - vous obtenez un pointeur valide et non nul. Bien sûr, vous ne pouvez pas utiliser le pointeur pour accéder à ce qu'il pointe sans invoquer un comportement indéfini.
Quant à savoir pourquoi cela existe, c'est pratique pour certains algorithmes et cela signifie que vous n'avez pas besoin d'encombrer votre code de tests pour les valeurs nulles.