Réponses:
Selon les spécifications, malloc (0) renverra "un pointeur nul ou un pointeur unique qui peut être passé avec succès à free ()".
Cela vous permet en gros de n'allouer rien, mais de passer la variable "artist" à un appel à free () sans souci. Pour des raisons pratiques, c'est à peu près la même chose que de faire:
artist = NULL;
La norme C (C17 7.22.3 / 1) dit:
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 retourné ne doit pas être utilisé pour accéder à un objet.
Donc, malloc(0)
pourrait retourner NULL
ou un pointeur valide qui ne peut pas être déréférencé . Dans les deux cas, il est parfaitement valable de faire appel free()
à lui.
Je ne pense pas vraiment malloc(0)
avoir beaucoup d'utilité, sauf dans les cas où il malloc(n)
est appelé dans une boucle par exemple, et n
peut être nul.
En regardant le code dans le lien, je pense que l'auteur avait deux idées fausses:
malloc(0)
renvoie toujours un pointeur valide , etfree(0)
est mauvais.Ainsi, il s'est assuré que cela artist
et d'autres variables avaient toujours une valeur «valide» en eux. Le commentaire dit autant: // these must always point at malloc'd data
.
malloc(0)
retourné un pointeur valide, alors malloc()
retourner NULL
signifie toujours "échec", et 0
n'est plus un cas particulier, ce qui est plus cohérent.
malloc
échec d'obtention de la mémoire sont définies par l'implémentation, une implémentation pourrait simplement définir que les allocations de taille 0 sont toujours insatisfiables ( ENOMEM
), et que maintenant malloc(0)
retourner 0 (avec errno==ENOMEM
) est cohérent. :-)
realloc
un pointeur renvoyé par malloc(0)
? Pouvez-vous realloc((char*)NULL)
?
Le comportement de malloc (0) est spécifique à l'implémentation. La bibliothèque peut renvoyer NULL ou avoir le comportement malloc normal, sans mémoire allouée. Quoi qu'il fasse, il doit être documenté quelque part.
Habituellement, il renvoie un pointeur valide et unique mais qui ne doit PAS être déréférencé. Notez également qu'il PEUT consommer de la mémoire même s'il n'a en fait rien alloué.
Il est possible de réallouer un pointeur malloc (0) non nul.
Avoir un verbatim malloc (0) n'est cependant pas très utile. Il est principalement utilisé lorsqu'une allocation dynamique est de zéro octet et que vous ne vous souciez pas de la valider.
malloc()
doit conserver quelque part des «informations de gestion» (cette taille du bloc alloué par exemple, et d'autres données auxiliaires). Donc, si malloc(0)
ne retourne pas NULL
, il utilisera la mémoire pour stocker ces informations, et sinon free()
d, constituera une fuite de mémoire.
malloc()
ne retournera, soit retourner NULL
.
malloc(0)
. Cependant, dans la même implémentation de la bibliothèque C standard, realloc(ptr, 0)
libère ptr
et retourne NULL.
Il y a une réponse ailleurs sur cette page qui commence "malloc (0) retournera une adresse mémoire valide et dont la plage dépendra du type de pointeur qui est alloué en mémoire". Cette déclaration est incorrecte (je n'ai pas assez de réputation pour commenter cette réponse directement, je ne peux donc pas mettre ce commentaire directement en dessous).
Faire malloc (0) n'allouera pas automatiquement de la mémoire de taille correcte. La fonction malloc ne sait pas dans quoi vous lancez son résultat. La fonction malloc repose uniquement sur le numéro de taille que vous donnez comme argument. Vous devez faire malloc (sizeof (int)) pour obtenir suffisamment de stockage pour contenir un int, par exemple pas 0.
malloc(0)
Cela n'a aucun sens pour moi, à moins que le code ne repose sur un comportement spécifique à l'implémentation. Si le code est destiné à être portable, il doit tenir compte du fait qu'un retour NULL de malloc(0)
n'est pas un échec. Alors, pourquoi ne pas simplement attribuer NULL à de artist
toute façon, car c'est un résultat réussi valide, il contient moins de code et que vos programmeurs de maintenance ne prendront pas le temps de le comprendre?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
ou malloc(some_variable_which_might_be_zero)
peut - être pourraient avoir leurs utilisations, même si encore une fois vous devez faire très attention à ne pas traiter un retour NULL comme un échec si la valeur est 0, mais une taille 0 est censée être OK.
Il y a beaucoup de demi-vraies réponses ici, alors voici les faits concrets. La page de manuel de malloc()
dit:
Si la taille est 0, alors malloc () renvoie NULL ou une valeur de pointeur unique qui peut être transmise ultérieurement avec succès à free ().
Cela signifie qu'il n'y a absolument aucune garantie que le résultat de malloc(0)
soit unique ou non NULL. La seule garantie est fournie par la définition de free()
, encore une fois, voici ce que dit la page de manuel:
Si ptr est NULL, aucune opération n'est effectuée.
Ainsi, quel que soit le malloc(0)
retour, il peut être transmis en toute sécurité free()
. Mais un NULL
pointeur aussi.
Par conséquent, l'écriture artist = malloc(0);
n'est en aucun cas meilleure que l'écriture artist = NULL;
malloc(0)
pourrait renvoyer, disons, 0x1, et free()
pourrait avoir une vérification de cas spécial de 0x1 comme il l'a fait pour 0x0.
NULL
, ou un pointeur unique". au lieu de "un pointeur nul ou un pointeur vers l'espace alloué". Il n'y a pas d' exigence unique . OTOH, renvoyer une valeur spéciale non unique peut perturber le code qui compte sur des valeurs uniques. Peut-être une question de cas de coin pour SO.
man
peut également documenter la forme définie par l'implémentation utilisée dans * nix. Dans ce cas, ce n'est pas le cas, mais ce n'est toujours pas une source canonique pour le général C.
Pourquoi tu ne devrais pas faire ça ...
Puisque la valeur de retour de malloc dépend de l'implémentation, vous pouvez récupérer un pointeur NULL ou une autre adresse. Cela peut finir par créer des débordements de mémoire tampon si le code de gestion des erreurs ne vérifie pas à la fois la taille et la valeur renvoyée, ce qui entraîne des problèmes de stabilité (plantages) ou même des problèmes de sécurité pires.
Considérez cet exemple, où un accès supplémentaire à la mémoire via l'adresse renvoyée endommagera le tas si la taille du tas est égale à zéro et l'implémentation renvoie une valeur non NULL.
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 */
}
Voir cette page de codage sécurisé de CERT Coding Standards où j'ai pris l'exemple ci-dessus pour plus de lecture.
Certes, je n'ai jamais vu cela auparavant, c'est la première fois que je vois cette syntaxe, pourrait-on dire, un cas classique de surpuissance des fonctions. En conjonction avec la réponse de Reed, je voudrais souligner qu'il existe une chose similaire, qui ressemble à une fonction surchargée realloc
:
realloc(foo, size);
. Lorsque vous passez un pointeur non NULL et une taille de zéro à realloc, realloc se comporte comme si vous aviez appelé free (…)realloc(foo, size);
,. Lorsque vous passez un pointeur NULL et que la taille est différente de zéro, realloc se comporte comme si vous aviez appelé malloc (…)J'espère que cela aide, Meilleures salutations, Tom.
malloc (0) retournera NULL ou un pointeur valide qui peut être correctement passé à free. Et même s'il semble que la mémoire vers laquelle elle pointe est inutile ou ne peut pas être écrite ou lue, ce n'est pas toujours vrai. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
On s'attend à un défaut de segmentation ici, mais étonnamment, cela imprime 100! C'est parce que malloc demande en fait une énorme quantité de mémoire lorsque nous appelons malloc pour la première fois. Chaque appel à malloc après cela utilise la mémoire de ce gros morceau. Ce n'est qu'après que cet énorme morceau est terminé, une nouvelle mémoire est demandée.
Utilisation de malloc (0): si vous êtes dans une situation où vous voulez que les appels de malloc suivants soient plus rapides, appeler malloc (0) devrait le faire pour vous (sauf pour les cas extrêmes).
*i
peut ne pas planter dans votre cas, mais c'est néanmoins un comportement non défini. Attention aux démons nasillards!
malloc(0)
qui n'est pas mentionnée. Sur les implémentations où il renvoie une valeur non NULL, en particulier dans une construction DEBUG, il alloue probablement PLUS que ce que vous avez demandé et vous donne le pointeur juste après son en-tête interne. Cela vous permet d'avoir une idée de l'utilisation réelle de la mémoire si vous obtenez cela avant et après une série d'allocations. par exemple: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
ou certains tels.
malloc(0)
. Pouvez-vous nous dire à quel chapitre vous parlez également? Fournir un devis exact serait également bien.
Sous Windows:
void *p = malloc(0);
allouera un tampon de longueur nulle sur le tas local. Le pointeur renvoyé est un pointeur de tas valide.malloc
appelle finalement en HeapAlloc
utilisant le tas d'exécution C par défaut qui appelle ensuite RtlAllocateHeap
, etc.free(p);
utilise HeapFree
pour libérer le tampon de longueur 0 sur le tas. Ne pas le libérer entraînerait une fuite de mémoire.C'est en fait très utile, et (évidemment à mon humble avis), le comportement autorisé de renvoyer un pointeur NULL est cassé. Un pointeur dynamique est utile non seulement pour ce sur quoi il pointe, mais aussi pour le fait que son adresse est unique. Renvoyer NULL supprime cette deuxième propriété. Tous les programmes intégrés de mallocs I (assez fréquemment en fait) ont ce comportement.
Pas sûr, selon un code source aléatoire de malloc que j'ai trouvé, une entrée de 0 entraîne une valeur de retour NULL. C'est donc une façon folle de régler le pointeur de l'artiste sur NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Voici l'analyse après exécution avec l'outil de vérification de la mémoire valgrind.
==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
et voici mon exemple de code:
#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;
}
Par défaut, 1024 octets sont alloués. Si j'augmente la taille de malloc, les octets alloués augmenteront de 1025 et ainsi de suite.
D'après la réponse de Reed Copsey et la page de manuel de malloc, j'ai écrit quelques exemples à tester. Et j'ai découvert que malloc (0) lui donnera toujours une valeur unique. Voir mon exemple:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
La sortie sera "Vous avez un pointeur valide", ce qui signifie qu'il ptr
n'est pas nul.
malloc(0)
renverra une adresse mémoire valide et dont la plage dépendra du type de pointeur auquel la mémoire est allouée. Vous pouvez également attribuer des valeurs à la zone de mémoire, mais cela doit être dans la plage avec le type de pointeur utilisé. Vous pouvez également libérer la mémoire allouée. Je vais expliquer cela avec un exemple:
int *p=NULL;
p=(int *)malloc(0);
free(p);
Le code ci-dessus fonctionnera correctement dans un gcc
compilateur sur une machine Linux. Si vous avez un compilateur 32 bits, vous pouvez fournir des valeurs dans la plage entière, c'est-à-dire -2147483648 à 2147483647. Il en va de même pour les caractères. Veuillez noter que si le type de pointeur déclaré est modifié, la plage de valeurs changera quel que soit le malloc
typage, c'est-à-dire
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
prendra une valeur de 0 à 255 de char car il est déclaré un int non signé.
malloc()
ne sait rien de la distribution (qui est en fait entièrement superfluente en C). Le déréférencement de la valeur de retour de malloc(0)
provoquera un comportement indéfini.
Juste pour corriger une fausse impression ici:
artist = (char *) malloc(0);
ne reviendra jamais NULL
; ce n'est pas la même chose que artist = NULL;
. Écrivez un programme simple et comparez artist
avec NULL
. if (artist == NULL)
est faux et if (artist)
vrai.