Question Différence entre malloc et calloc?


Quelle est la différence entre faire:

ptr = (char **) malloc (MAXELEMS * sizeof(char *));

ou:

ptr = (char **) calloc (MAXELEMS, sizeof(char*));

Quand est-ce une bonne idée d'utiliser calloc sur malloc ou vice versa?


629
2017-10-08 15:04


origine


Réponses:


calloc() zéro-initialise le tampon, tandis que malloc() laisse la mémoire non initialisée.

MODIFIER:

La mise à zéro de la mémoire peut prendre un peu de temps, donc vous voulez probablement utiliser malloc() si cette performance est un problème. Si l'initialisation de la mémoire est plus importante, utilisez calloc(). Par exemple, calloc() pourrait vous faire économiser un appel à memset().


711
2017-10-08 15:05



Une différence moins connue est que dans les systèmes d'exploitation avec allocation de mémoire optimiste, comme Linux, le pointeur retourné par malloc n'est pas sauvegardé par la mémoire réelle avant que le programme ne la touche réellement.

calloc Effectivement, il touche la mémoire (il écrit des zéros dessus) et ainsi vous serez sûr que le système d'exploitation sauvegarde l'allocation avec de la RAM réelle (ou swap). C'est aussi pourquoi il est plus lent que malloc (non seulement il doit le mettre à zéro, le système d'exploitation doit également trouver une zone de mémoire appropriée en échangeant éventuellement d'autres processus)

Voir par exemple cette question SO pour une discussion plus approfondie sur le comportement de malloc


315
2017-10-18 20:44



Un avantage souvent négligé de calloc est que (implémentations conformes de) il vous aidera à vous protéger contre les vulnérabilités de débordement d'entier. Comparer:

size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);

contre.

size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);

Le premier pourrait entraîner une allocation minuscule et les dépassements de tampon suivants, si count est supérieur à SIZE_MAX/sizeof *bar. Ce dernier échouera automatiquement dans ce cas, car un objet de grande taille ne peut pas être créé.

Bien sûr, vous devez être à l'affût des implémentations non conformes qui ignorent simplement la possibilité de débordement ... Si c'est un problème sur les plateformes que vous ciblez, vous devrez quand même faire un test manuel pour débordement.


96
2017-08-13 16:53



La documentation fait ressembler le calloc à malloc, ce qui ne fait qu'initialiser la mémoire; ce n'est pas la principale différence! L'idée de calloc est d'abstenir la sémantique copy-on-write pour l'allocation de mémoire. Lorsque vous allouez de la mémoire avec calloc, tout est mappé à la même page physique qui est initialisée à zéro. Lorsque l'une des pages de la mémoire allouée est écrite dans une page physique est allouée. Ceci est souvent utilisé pour faire d'ÉNORMES tables de hachage, par exemple puisque les parties de hachage qui sont vides ne sont pas soutenues par de la mémoire supplémentaire (pages); ils pointent joyeusement vers la seule page initialisée à zéro, qui peut même être partagée entre les processus.

Toute écriture dans une adresse virtuelle est mappée sur une page, si cette page est la page zéro, une autre page physique est allouée, la page zéro est copiée et le flux de contrôle est renvoyé au processus client. Cela fonctionne de la même façon que les fichiers mappés en mémoire, la mémoire virtuelle, etc. fonctionnent .. il utilise la pagination.

Voici une histoire d'optimisation sur le sujet: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/


26
2017-08-15 11:16



Il n'y a pas de différence dans la taille du bloc de mémoire alloué. calloc remplit juste le bloc de mémoire avec le modèle physique tout-zéro-bits. En pratique, on suppose souvent que les objets situés dans le bloc mémoire callocavoir une valeur initiale comme si elles étaient initialisées avec littéral 0, c'est-à-dire que les entiers doivent avoir une valeur de 0, variables à virgule flottante - valeur de 0.0, pointeurs - la valeur null-pointeur appropriée, et ainsi de suite.

Du point de vue pédant, cependant, calloc (aussi bien que memset(..., 0, ...)) est seulement garanti pour initialiser correctement (avec des zéros) des objets de type unsigned char. Tout le reste n'est pas garanti pour être correctement initialisé et peut contenir ce qu'on appelle représentation de piège, ce qui provoque un comportement indéfini. En d'autres termes, pour tout type autre que unsigned char le modèle de tout-zéro bits mentionné ci-dessus peut représenter une valeur illégale, une représentation de piège.

Plus tard, dans l'un des corrigenda technique à la norme C99, le comportement a été défini pour tous les types d'entiers (ce qui est logique). C'est à dire. formellement, dans le langage C actuel, vous pouvez initialiser uniquement les types entiers avec calloc (et memset(..., 0, ...)). L'utiliser pour initialiser n'importe quoi d'autre dans un cas général conduit à un comportement indéfini, du point de vue du langage C.

En pratique, calloc fonctionne, comme nous le savons tous :), mais si vous voulez l'utiliser (compte tenu de ce qui précède) est à vous. Personnellement, je préfère l'éviter complètement, utiliser malloc à la place et effectuer ma propre initialisation.

Enfin, un autre détail important est que calloc est nécessaire pour calculer la taille finale du bloc intérieurement, en multipliant la taille de l'élément par le nombre d'éléments. En faisant cela, calloc doit surveiller un éventuel débordement arithmétique. Cela entraînera une allocation infructueuse (pointeur nul) si la taille de bloc demandée ne peut pas être calculée correctement. Pendant ce temps, votre malloc la version ne fait aucune tentative de surveiller le débordement. Il allouera une quantité de mémoire "imprévisible" en cas de débordement.


24
2017-10-18 20:59



d'un article Benchmarking amusant avec calloc () et zéro pages sur Le blog de Georg Hager 

Lorsque vous allouez de la mémoire à l'aide de calloc (), la quantité de mémoire demandée n'est pas immédiatement allouée. Au lieu de cela, toutes les pages qui appartiennent au bloc de mémoire sont connectées à une seule page contenant tous les zéros par une magie MMU (liens ci-dessous). Si ces pages sont seulement lues (ce qui était vrai pour les tableaux b, c et d dans la version originale du benchmark), les données sont fournies à partir de la page à zéro unique, qui - bien sûr - entre dans la mémoire cache. Voilà pour les noyaux de boucles liés à la mémoire. Si une page est écrite (peu importe comment), une erreur se produit, la page "réelle" est mappée et la page zéro est copiée en mémoire. C'est ce qu'on appelle la copie sur écriture, une approche d'optimisation bien connue (que j'ai même enseignée plusieurs fois dans mes cours en C ++). Après cela, l'astuce de lecture zéro ne fonctionne plus pour cette page et c'est pourquoi les performances étaient beaucoup plus faibles après l'insertion de la boucle init - supposée redondante.


16
2017-08-28 05:51



calloc est généralement malloc+memset à 0

Il est généralement légèrement préférable d'utiliser malloc+memset explicitement, surtout quand vous faites quelque chose comme:

ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));

C'est mieux parce que sizeof(Item) est connu du compilateur au moment de la compilation et le compilateur le remplacera dans la plupart des cas par les meilleures instructions possibles à zéro mémoire. D'autre part si memset se passe dans calloc, la taille du paramètre de l'allocation n'est pas compilée dans le calloc code et réel memset est souvent appelé, qui contient généralement le code à remplir octet par octet jusqu'à long terme, que le cycle pour remplir la mémoire dans sizeof(long) morceaux et enfin octet par byte remplir de l'espace restant. Même si l'allocateur est assez intelligent pour appeler certains aligned_memset Ce sera toujours une boucle générique.

Une exception notable serait lorsque vous faites malloc / calloc d'un très gros morceau de mémoire (certains power_of_two kilo-octets) dans quel cas l'allocation peut être faite directement à partir du noyau. Comme les noyaux OS vont typiquement mettre à zéro toute la mémoire qu'ils donnent pour des raisons de sécurité, un calloc assez intelligent pourrait juste le renvoyer avec une mise à zéro additionnelle. Encore une fois - si vous allouez juste quelque chose que vous savez est petit, vous pouvez être mieux avec malloc + memset performance-sage.


10
2017-08-16 21:46



malloc() alloue un bloc de mémoire de taille donnée (en octets) et retourne un pointeur au début du bloc.

void *malloc(size_t size);

malloc() n'initialise pas la mémoire allouée.

calloc() alloue la mémoire et initialise la mémoire allouée à tous les bits zéro.

void *calloc(size_t num, size_t size);

9
2017-10-26 07:01