qu'est-ce que malloc (0) retour? [dupliquer]
Question
Cette question a déjà une réponse ici:
- quel est le point malloc (0)? 17 réponses
Qu'est-ce que retourne malloc(0)
? La réponse serait-même pour realloc(malloc(0),0)
?
#include<stdio.h>
#include<malloc.h>
int main()
{
printf("%p\n", malloc(0));
printf("%p\n", realloc(malloc(0), 0));
return 0;
}
Sortie de gcc Linux:
manav@manav-workstation:~$ gcc -Wall mal.c
manav@manav-workstation:~$ ./a.out
0x9363008
(nil)
manav@manav-workstation:~$
La sortie à chaque fois pour continuer à changer malloc(0)
. Est-ce une réponse standard? Et pourquoi quelqu'un serait intéressé à obtenir un pointeur, autre que la recherche universitaire?
EDIT:
Si malloc(0)
renvoie un pointeur factice, alors comment ne fonctionne suivant:
int main()
{
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
return 0;
}
EDIT:
Le code suivant renvoie « possible » pour chaque itération. Pourquoi devrait-il pas l'échec?
#include<stdio.h>
#include<malloc.h>
int main()
{
int i;
void *ptr;
printf("Testing using BRUTE FORCE\n");
for (i=0; i<65000; i++)
{
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
printf("Iteration %d: possible\n", i);
else
{
printf("Failed for iteration %d\n", i);
break;
}
}
return 0;
}
La solution
D'autres ont répondu à la façon dont fonctionne malloc(0)
. Je vais répondre à l'une des questions que vous avez posées qui n'a pas encore reçu de réponse (je pense). La question est sur le point realloc(malloc(0), 0)
:
Qu'est-ce
malloc(0)
retour? La réponse serait-même pourrealloc(malloc(0),0)
?
La norme dit ceci au sujet realloc(ptr, size)
:
- si
ptr
estNULL
, il se comporte commemalloc(size)
, - sinon (
ptr
n'est pasNULL
), il libère l'ancien pointeur d'objet parptr
et renvoie un pointeur vers un nouveau tampon alloué. Mais sisize
est 0, C89 dit que l'effet est équivalent àfree(ptr)
. Fait intéressant, je ne trouve pas cette déclaration dans le projet de C99 (ou n1256 n1336). En C89, la seule valeur raisonnable pour revenir dans ce cas seraitNULL
.
Alors, il y a deux cas:
- retourne
malloc(0)
NULL
sur une mise en œuvre. Ensuite, votre appelrealloc()
est équivalent àrealloc(NULL, 0)
. Cela équivaut àmalloc(0)
d'en haut (et qui estNULL
dans ce cas). -
malloc(0)
retourne nonNULL
. Ensuite, l'appel est équivalent àfree(malloc(0))
. Dans ce cas,malloc(0)
etrealloc(malloc(0), 0)
sont pas équivalent.
Notez qu'il ya un cas intéressant: dans le second cas, lorsque malloc(0)
retourne non NULL
en cas de succès, il peut encore revenir NULL
pour indiquer l'échec. Cela se traduira par un appel comme:. realloc(NULL, 0)
, ce qui équivaudrait à malloc(0)
, qui peut ou ne peut pas revenir NULL
Je ne sais pas si l'omission dans C99 est un oubli ou si cela signifie que dans C99, realloc(ptr, 0)
pour NULL
non ptr
ne correspond pas à free(ptr)
. Je viens d'essayer cela avec gcc -std=c99
, et ce qui précède équivaut à free(ptr)
.
Modifier : Je pense que je comprends ce que votre confusion est:
Regardons un extrait de votre code exemple:
ptr = malloc(0);
if (ptr == realloc(ptr, 1024))
Le ci-dessus ne sont pas les mêmes que malloc(0) == realloc(malloc(0), 1024)
. Dans le second, l'appel malloc()
est fait deux fois, alors que dans le premier, vous passez un pointeur précédemment alloué à realloc()
.
Analysons le premier code d'abord. En supposant malloc(0)
ne retourne pas NULL
sur la réussite, ptr
a une valeur valide. Lorsque vous faites realloc(ptr, 1024)
, realloc()
vous donne essentiellement un nouveau tampon qui a la taille 1024, et la ptr
devient invalide. Une mise en œuvre conforme peut retourner la même adresse que celle déjà ptr
. Donc, votre état de if
peut retourner vrai. (Notez, cependant, regardant la valeur de ptr
après realloc(ptr, 1024)
peut être un comportement non défini.)
Maintenant, la question que vous posez: malloc(0) == realloc(malloc(0), 1024)
. Dans ce cas, supposons que les deux malloc(0)
LHS et RHS retourne non NULL
. Ensuite, ils sont garantis différents. En outre, la valeur de retour de malloc()
sur le LHS n'a pas été free()
d encore, de sorte que toute autre malloc()
, calloc()
ou realloc()
ne peut retourner cette valeur. Cela signifie que si vous avez écrit votre condition:
if (malloc(0) == realloc(malloc(0), 1024)
puts("possible");
vous ne verrez pas possible
sur la sortie (à moins que malloc()
et realloc()
échouent et renvoient 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;
}
Sur OS X, mon code n'a rien affiché quand je l'ai couru. Sous Linux, il imprime possible, OK
.
Autres conseils
malloc(0)
est Mise en œuvre Defined en ce qui concerne C99.
De C99 [Section 7.20.3]
L'ordre et la contiguïté de stockage alloué par les appels successifs à la calloc, malloc et fonctions realloc est fi ée eci . Le pointeur retourné si l'allocation succède est convenablement aligné de sorte qu'il peut être affecté à un pointeur sur tout type d'objet et ensuite utilisé pour accéder à un tel objet ou un ensemble de tels objets dans l'espace alloué (Jusqu'à ce que l'espace est explicitement désallouée). La durée de vie d'un objet alloué étend de l'allocation jusqu'à ce que la désaffectation. Chaque telle attribution doit donner un pointeur sur un objet disjoint de tout autre objet. Le pointeur est retourné des points au début (octet le plus bas adresse) de l'espace alloué. Si l'espace ne peut être alloué, un pointeur NULL est revenu. Si la taille de l'espace est zéro, le comportement est l'implémentation dé fi nies : soit un pointeur NULL est renvoyé, ou le comportement est comme si la taille était un peu valeur non nulle, sauf que le pointeur retourné ne doit pas être utilisé pour accéder à un objet.
En C89, malloc (0) dépend de l'implémentation - Je ne sais pas si C99 a fixé ou non. En C ++, en utilisant:
char * p = new char[0];
est bien défini - vous obtenez un valide, pointeur non nul. Bien sûr, vous ne pouvez pas utiliser le pointeur pour accéder à ce qu'il pointe vers sans invoquer un comportement non défini.
Quant à savoir pourquoi il existe, il est commode pour certains algorithmes, et signifie que vous n'avez pas besoin de litière de votre code avec des tests pour des valeurs nulles.
norme C99
Si l'espace ne peut être alloué, un nullpointer est retourné. Si la taille de l'espace est zéro, le comportement est défini par l'implémentation: soit un pointeur nul est retourné, ou le comportement est comme si la taille était une valeur non nulle, sauf que la pointeur retourné ne doit pas être utilisé pour accéder à un objet.
Le comp.lang.c FAQ a suivante pour dire:
La norme ANSI / ISO dit qu'il peut soit faire; le comportement est la mise en œuvre défini (voir la question 11,33). Code Portable doit soit prendre soin de ne pas appeler malloc (0), ou être préparé pour la possibilité d'une valeur nulle retour.
Alors, il est probablement préférable d'éviter d'utiliser malloc(0)
.
Voir C99, section 7.20.3:
Si la taille de l'espace requis est zéro, le comportement est implementationdefined: soit une valeur nulle pointeur est retourné, ou le comportement est comme si la taille était un peu différent de zéro valeur, sauf que le retour pointeur ne doit pas être utilisé pour accéder à un objet.
Ceci est valable pour les trois fonctions d'allocation (c.-à-calloc()
, malloc()
et realloc()
).
Un point personne ne se souciait de parler encore, dans votre premier programme est que realloc
longueur 0 est la même chose que free
.
à partir de la page de manuel Solaris:
La fonction
realloc()
modifie la taille du bloc a parptr
àsize
octets et renvoie un pointeur vers le bloc (éventuellement déplacé). Le contenu ne changera pas jusqu'à la moindre des nouvelles et anciennes tailles. Siptr
estNULL
,realloc()
se comporte commemalloc()
de la taille spécifiée. Sisize
est0
etptr
est pas un pointeur NULL, l'espace pointé est fait disponible pour plus d'allocation par l'application, bien que pas retourné au système. La mémoire est renvoyée au système seulement à la fin de l'application.
Si on ne sait pas qu'il peut être une source de mauvaise surprise (qui est arrivé à moi).
Je pense que cela dépend. J'ai vérifié les sources visuelles Studio 2005 et a vu cela dans la fonction _heap_alloc:
if (size == 0)
size = 1;
Je pense que dans de nombreux cas, vous voudrez peut-être un pointeur valide, même lorsque vous demandez zéro octets. En effet, ce comportement cohérent facilite de vérifier vos pointeurs parce que: si vous avez un pointeur non NULL il est OK; si vous avez un pointeur NULL vous avez probablement un problème. Voilà pourquoi je pense que la plupart des implémentations renvoient un pointeur valide, même lorsque vous demandez zéro octets.
Si malloc (0) renvoie un pointeur factice, alors comment ne fonctionne suivant:
void *ptr = malloc(0);
printf("%p\n", realloc(ptr, 1024));
Je ne sais pas ce que vous entendez par « pointeur factice ». Si malloc(0)
renvoie une valeur non NULL, alors ptr
est un pointeur valide à un bloc de mémoire de taille zéro. La mise en œuvre de malloc
enregistre ces informations d'une manière spécifique à la mise en œuvre. realloc
connaît le chemin (spécifique à la mise en œuvre) pour savoir que les points de ptr
à un bloc de mémoire de taille zéro.
(Comment malloc
/ realloc
/ free
Une possibilité est d'allouer 4 octets de plus que demandé et stocker la taille faire est spécifique à la mise en œuvre. Juste avant le bloc de mémoire. Dans ce cas, ((int *)ptr)[-1]
donnerait la taille du bloc de mémoire, qui est 0
. Vous ne devriez jamais faire cela à partir de votre code, il est seulement pour une utilisation par realloc
et free
).