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 inversement?
calloc()
initialise le tampon à zéro, tandis que malloc()
laisse la mémoire non initialisée.
EDIT:
La remise à zéro de la mémoire peut prendre un peu de temps, vous voudrez donc probablement utiliser malloc()
si cette performance pose problème. Si l'initialisation de la mémoire est plus importante, utilisez calloc()
. Par exemple, calloc()
peut vous faire économiser un appel à memset()
.
Une différence moins connue est que, dans les systèmes d'exploitation à allocation de mémoire optimiste, comme Linux, le pointeur renvoyé par malloc
n'est pas sauvegardé par de la mémoire réelle tant que le programme ne l'a pas réellement touché.
calloc
touche effectivement la mémoire (elle écrit des zéros) et vous serez ainsi assuré que le système d'exploitation sauvegarde l'allocation avec la valeur réelle RAM (ou swap). C’est aussi pourquoi il est plus lent que malloc (non seulement il doit le mettre à zéro, mais le système d’exploitation doit également trouver une zone mémoire appropriée en échangeant éventuellement d’autres processus).
Voir par exemple cette SO question pour une discussion plus approfondie sur le comportement de malloc
Un avantage souvent négligé de calloc
est que (implémentations conformes de) cela vous aidera à vous protéger contre les vulnérabilités de dépassement d'entier. Comparer:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
vs.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
Le premier pourrait entraîner une petite allocation et des dépassements de tampon ultérieurs, si count
est supérieur à SIZE_MAX/sizeof *bar
. Ce dernier échouera automatiquement dans ce cas car un objet de cette taille ne peut pas être créé.
Bien entendu, vous devrez peut-être rechercher des implémentations non conformes qui ignorent tout simplement la possibilité de débordement ... S'il s'agit d'un problème sur les plates-formes que vous ciblez, vous devrez quand même effectuer un test manuel du débordement.
La documentation donne à l'appel un aspect ressemblant à malloc, qui initialise simplement la mémoire à zéro; Ce n'est pas la principale différence! L'idée de calloc est de s'abstenir de sémantique de copie sur écriture pour l'allocation de mémoire. Lorsque vous allouez de la mémoire avec calloc, tout est mappé sur la même page physique, qui est initialisée à zéro. Lorsqu'une des pages de la mémoire allouée est écrite dans une page physique, elle est allouée. Ceci est souvent utilisé pour créer d'énormes tables de hachage, par exemple puisque les parties de hachage vides ne sont pas sauvegardées par aucune mémoire supplémentaire (pages); ils désignent heureusement la page unique initialisée à zéro, qui peut même être partagée entre des 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 y est copiée et le flux de contrôle est renvoyé au processus client. Cela fonctionne de la même manière que les fichiers mappés en mémoire, la mémoire virtuelle, etc., il utilise la pagination.
Voici un article d'optimisation sur le sujet: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
Il n'y a pas de différence dans la taille du bloc de mémoire alloué. calloc
remplit simplement le bloc de mémoire avec un modèle physique de bits nuls. En pratique, on suppose souvent que les objets situés dans le bloc mémoire alloué avec calloc
ont une valeur initiale comme s'ils étaient initialisés avec le littéral 0
, c'est-à-dire que les entiers doivent avoir la valeur 0
, float -point variables - valeur de 0.0
, pointeurs - la valeur appropriée de null-pointeur, etc.
Du point de vue du pédant, cependant, calloc
(ainsi que memset(..., 0, ...)
) ne garantit que l’initialisation correcte (avec des zéros) des objets de type unsigned char
. Tout le reste n'est pas garanti d'être correctement initialisé et peut contenir ce qu'on appelle représentation d'interruption, ce qui provoque un comportement indéfini. En d’autres termes, pour tout type autre que unsigned char
, le modèle susmentionné contenant uniquement des bits nuls pourrait représenter une valeur non conforme, la représentation de déroutement.
Plus tard, dans l’un des corrigenda techniques à 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 ne pouvez initialiser que les types entiers avec calloc
(et memset(..., 0, ...)
). Son utilisation pour initialiser quoi que ce soit d'autre dans le 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 c'est à vous de décider si vous souhaitez l'utiliser (compte tenu de ce qui précède). Personnellement, je préfère l'éviter complètement, utilisez plutôt malloc
et effectuez ma propre initialisation.
Enfin, un autre détail important est que calloc
est nécessaire pour calculer la taille finale du bloc en interne, en multipliant la taille d'élément par le nombre d'éléments. Ce faisant, calloc
doit surveiller les débordements arithmétiques. L'allocation échouera (pointeur NULL) si la taille de bloc demandée ne peut pas être calculée correctement. Pendant ce temps, votre version malloc
ne tente pas de surveiller les débordements. Il allouera une quantité de mémoire "imprévisible" en cas de débordement.
à partir d'un article Benchmarking fun avec calloc () et zéro pages sur Blog de Georg Hager
Lors de l'allocation de mémoire à l'aide de calloc (), la quantité de mémoire demandée n'est pas allouée immédiatement. Au lieu de cela, toutes les pages appartenant au bloc de mémoire sont connectées à une seule page contenant tous les zéros par une certaine magie MMU (liens ci-dessous). Si ces pages ne sont que lues (ce qui était le cas pour les tableaux b, c et d de la version d'origine du test), les données sont fournies à partir de la page à zéro unique, qui - bien sûr - s'inscrit dans le cache. Voilà pour les noyaux de boucle liés à la mémoire. Si une page est écrite (quelle que soit la méthode), 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 de C++). Après cela, l’astuce de lecture zéro ne fonctionne plus pour cette page et c’est pourquoi les performances étaient tellement plus faibles après l’insertion de la boucle - supposément redondante - init.
calloc
est généralement malloc+memset
à 0
Il est généralement préférable d’utiliser explicitement malloc+memset
, en particulier lorsque vous faites quelque chose comme:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
C’est mieux car 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 jusqu’à zéro mémoire. Par contre, si memset
se produit dans calloc
, la taille du paramètre de l’attribution n’est pas compilée dans le code calloc
, et l’appel réel memset
s’appelle contiennent généralement du code permettant d'effectuer un remplissage octet par octet jusqu'à une limite longue, puis d'effectuer un cycle permettant de remplir la mémoire dans des morceaux sizeof(long)
et, enfin, un remplissage octet par octet de l'espace restant. Même si l'allocateur est assez intelligent pour appeler du aligned_memset
, ce sera toujours une boucle générique.
Une exception notable serait lorsque vous effectuez une opération malloc/calloc d'une très grande quantité de mémoire (quelques power_of_two kilo-octets), auquel cas l'allocation peut être effectuée directement à partir du noyau. Étant donné que les noyaux des systèmes d’exploitation mettent généralement à zéro la mémoire allouée pour des raisons de sécurité, un calloc suffisamment intelligent pourrait simplement le renvoyer avec une remise à zéro supplémentaire. Encore une fois - si vous allouez simplement quelque chose que vous savez être petit, il est peut-être préférable de choisir malloc + memset en termes de performances.
Différence 1:
malloc()
alloue généralement le bloc de mémoire et il s'agit d'un segment de mémoire initialisé.
calloc()
alloue le bloc mémoire et initialise tout le bloc mémoire à 0.
Différence 2:
Si vous considérez la syntaxe malloc()
, cela ne prendra qu'un argument. Considérez l'exemple suivant ci-dessous:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
Ex: si vous voulez allouer 10 blocs de mémoire pour le type int,
int *ptr = (int *) malloc(sizeof(int) * 10 );
Si vous considérez la syntaxe calloc()
, il faudra 2 arguments. Considérez l'exemple suivant ci-dessous:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
Ex: si vous voulez allouer 10 blocs de mémoire pour le type int et initialiser tout ça à ZERO,
int *ptr = (int *) calloc(10, (sizeof(int)));
Similarité:
malloc()
et calloc()
renverront par défaut void * s'ils ne sont pas typés.!
Il y a deux différences.
Premièrement, il s’agit du nombre d’arguments. malloc()
accepte un seul argument (mémoire requise en octets), alors que calloc()
nécessite deux arguments.
Deuxièmement, malloc()
n'initialise pas la mémoire allouée, alors que calloc()
initialise la mémoire allouée à ZERO.
calloc()
alloue une zone mémoire, la longueur sera le produit de ses paramètres. calloc
remplit la mémoire avec ZERO et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser suffisamment d'espace, il retourne un pointeur NULL
.Syntaxe: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
i.e. ptr_var=(type *)calloc(n,s);
malloc()
alloue un seul bloc de mémoire de REQUSTED SIZE et renvoie un pointeur sur le premier octet. S'il ne parvient pas à localiser la quantité de mémoire requise, il renvoie un pointeur null.Syntaxe: ptr_var=(cast_type *)malloc(Size_in_bytes);
La fonction malloc()
accepte un argument, qui est le nombre d'octets à allouer, tandis que la fonction calloc()
utilise deux arguments, l'un étant le nombre d'éléments et l'autre le nombre d'octets à allouer pour chacun de ces éléments. De même, calloc()
initialise l'espace alloué à zéro, alors que malloc()
ne le fait pas.
La fonction calloc()
déclarée dans l'en-tête <stdlib.h>
offre plusieurs avantages par rapport à la fonction malloc()
.
Une différence non encore mentionnée: taille limite
void *malloc(size_t size)
ne peut allouer que jusqu'à SIZE_MAX
.
void *calloc(size_t nmemb, size_t size);
peut allouer environ SIZE_MAX*SIZE_MAX
.
Cette capacité n'est pas souvent utilisée sur de nombreuses plates-formes à adressage linéaire. De tels systèmes limitent calloc()
avec nmemb * size <= SIZE_MAX
.
Considérons un type de 512 octets appelé disk_sector
et le code veut utiliser beaucoup de secteurs. Ici, le code ne peut utiliser que jusqu'à SIZE_MAX/sizeof disk_sector
secteurs.
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
Considérez ce qui suit qui permet une allocation encore plus grande.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
Maintenant, si un tel système peut fournir une allocation aussi importante, c’est un autre problème. La plupart aujourd'hui ne le feront pas. Pourtant, cela fait plusieurs années que SIZE_MAX
était 65535. Étant donné loi de Moore , soupçonnez que cela se produira vers 2030 avec certains modèles de mémoire avec SIZE_MAX == 4294967295
et des pools de mémoire dans le 100 de GBytes.
malloc()
et calloc()
sont des fonctions de la bibliothèque standard C qui permettent l'allocation dynamique de mémoire, ce qui signifie qu'elles permettent également l'allocation de mémoire pendant l'exécution.
Leurs prototypes sont les suivants:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
Il y a principalement deux différences entre les deux:
Comportement: malloc()
alloue un bloc de mémoire, sans l'initialiser, et la lecture du contenu de ce bloc produira des valeurs parasites. calloc()
, d’autre part, alloue un bloc de mémoire et l’initialise à zéro. Bien entendu, la lecture du contenu de ce bloc donnera lieu à des zéros.
Syntaxe: malloc()
prend 1 argument (la taille à allouer) et calloc()
prend deux arguments (nombre de blocs à allouer et taille de chaque bloc).
La valeur renvoyée par les deux est un pointeur sur le bloc de mémoire alloué, en cas de succès. Sinon, NULL sera renvoyé indiquant l'échec de l'allocation de mémoire.
Exemple:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
La même fonctionnalité que calloc()
peut être obtenue en utilisant malloc()
et memset()
:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
Notez que malloc()
est utilisé de préférence sur calloc()
car il est plus rapide. Si vous souhaitez initialiser les valeurs à zéro, utilisez plutôt calloc()
.
Nb de blocs:
malloc () Attribue un seul bloc de mémoire demandée,
calloc () Assigne plusieurs blocs de la mémoire demandée
Initialisation:
malloc () n'efface pas et n'initialise pas la mémoire allouée.
calloc () initialise la mémoire allouée par zéro.
Vitesse:
La vitesse de malloc () est rapide.
La vitesse de calloc () est comparativement lente.
Syntex:
void *malloc(size_t size); // syntex for malloc() function
void *calloc(size_t num, size_t size); // syntex for calloc() function
Argument:
Si vous considérez la syntaxe malloc (), cela ne prendra qu'un argument.
Si vous considérez la syntaxe calloc (), il faudra 2 arguments.
Manière de mémoire Allocation ::
La fonction malloc () attribue à la mémoire la taille souhaitée à partir du tas disponible.
calloc () attribue à la mémoire la taille de ce qui est égal à ‘num * size’.
Signification sur le nom:
Le nom malloc signifie attribué à l’allocation de mémoire.
Le nom calloc signifie attribution contiguë.