Differenza tra malloc e calloc?

Qual è la differenza tra fare:

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

o:

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

Quando è una buona idea usare calloc su malloc o viceversa?

calloc() azzera-inizializza il buffer, mentre malloc() lascia la memoria non inizializzata.

MODIFICARE:

Azzerare la memoria potrebbe richiedere un po ‘di tempo, quindi probabilmente vorrai usare malloc() se quella prestazione è un problema. Se l’inizializzazione della memoria è più importante, usa calloc() . Ad esempio, calloc() potrebbe salvarti una chiamata a memset() .

Una differenza meno nota è che nei sistemi operativi con allocazione ottimizzata della memoria, come Linux, il puntatore restituito da malloc non è supportato dalla memoria reale finché il programma non lo tocca effettivamente.

calloc infatti tocca la memoria (scrive zero su di essa) e quindi sarai sicuro che il sistema operativo stia supportando l’allocazione con RAM (o swap) effettiva. Questo è anche il motivo per cui è più lento di malloc (non solo deve azzerarlo, il sistema operativo deve anche trovare un’area di memoria adatta, eventualmente scambiando altri processi)

Si veda ad esempio questa domanda SO per ulteriori discussioni sul comportamento di malloc

Un vantaggio spesso trascurato di calloc è che (implementazioni conformi di) aiuterà a proteggerti dalle vulnerabilità di overflow di interi. Confrontare:

 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); 

Il primo potrebbe comportare una piccola allocazione e successivi buffer overflow, se il count è maggiore di SIZE_MAX/sizeof *bar . Quest’ultimo fallirà automaticamente in questo caso poiché non è ansible creare un object così grande.

Naturalmente potresti dover essere alla ricerca di implementazioni non conformi che semplicemente ignorano la possibilità di un overflow … Se questa è una preoccupazione per le piattaforms che scegli come target, dovrai comunque eseguire un test manuale per l’overflow.

La documentazione rende il calloc simile a malloc, che azzera appena la memoria; questa non è la differenza principale! L’idea di calloc è di asportare la semantica copy-on-write per l’allocazione della memoria. Quando si assegna memoria con calloc, tutto si associa alla stessa pagina fisica inizializzata a zero. Quando viene assegnata una qualsiasi delle pagine della memoria allocata in una pagina fisica. Questo è spesso usato per creare tabelle hash HUGE, ad esempio poiché le parti dell’hash che sono vuote non sono supportate da alcuna memoria extra (pagine); indicano felicemente la singola pagina inizializzata allo zero, che può essere anche condivisa tra i processi.

Qualsiasi scrittura sull’indirizzo virtuale viene mappata su una pagina, se quella pagina è la pagina zero, viene allocata un’altra pagina fisica, viene copiata la pagina zero e il stream di controllo viene restituito al processo client. Funziona allo stesso modo dei file mappati in memoria, della memoria virtuale, ecc. Funziona .. usa il paging.

Ecco una storia di ottimizzazione sull’argomento: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/

Non c’è differenza nella dimensione del blocco di memoria allocato. calloc riempie semplicemente il blocco di memoria con un modello fisico a zero bit. In pratica si presuppone spesso che gli oggetti situati nel blocco di memoria allocato con calloc abbiano valore initile come se fossero inizializzati con letterali 0 , cioè gli interi dovrebbero avere valore 0 , variabili in virgola mobile – valore di 0.0 , puntatori – l’appropriato valore del puntatore nullo e così via.

Dal punto di vista pedante, tuttavia, calloc (così come memset(..., 0, ...) ) è garantito solo per inizializzare correttamente (con zeri) oggetti di tipo unsigned char . Non è garantito che tutto il resto sia inizializzato correttamente e possa contenere la cosiddetta rappresentazione trap , che causa un comportamento indefinito. In altre parole, per qualsiasi tipo diverso dal unsigned char il patterm di tutti i bit zero menzionato sopra potrebbe rappresentare un valore non valido, rappresentazione di trap.

Successivamente, in uno degli standard della correzione tecnica allo standard C99, il comportamento è stato definito per tutti i tipi di interi (che ha senso). Cioè formalmente, nell’attuale linguaggio C è ansible inizializzare solo i tipi interi con calloc (e memset(..., 0, ...) ). Usarlo per inizializzare qualsiasi altra cosa nel caso generale porta a comportamenti non definiti, dal punto di vista del linguaggio C.

In pratica, calloc funziona, come tutti sappiamo :), ma se vuoi usarlo (considerando quanto sopra) dipende da te. Personalmente preferisco evitarlo completamente, usare invece malloc ed eseguire la mia inizializzazione.

Infine, un altro dettaglio importante è che calloc è necessario per calcolare internamente la dimensione finale del blocco, moltiplicando la dimensione dell’elemento per il numero di elementi. Mentre lo fa, calloc deve controllare il ansible trabocco aritmetico. Risulterà in un’assegnazione non riuscita (puntatore nullo) se la dimensione del blocco richiesta non può essere calcasting correttamente. Nel frattempo, la tua versione di malloc non fa alcun tentativo di guardare fuori campo. Assegnerà una quantità di memoria “imprevedibile” in caso di overflow.

da un articolo Benchmarking fun con calloc () e zero pagine sul blog di Georg Hager

Quando si assegna memoria utilizzando calloc (), la quantità di memoria richiesta non viene allocata immediatamente. Invece, tutte le pagine che appartengono al blocco di memoria sono collegate a una singola pagina contenente tutti gli zeri da qualche magia MMU (link sotto). Se tali pagine vengono lette solo (il che era vero per gli array b, ced della versione originale del benchmark), i dati sono forniti dalla pagina zero singolo, che – ovviamente – si inserisce nella cache. Così tanto per i kernel loop legati alla memoria. Se una pagina viene scritta (indipendentemente da come), si verifica un errore, la pagina “reale” viene mappata e la pagina zero viene copiata in memoria. Questo è chiamato copy-on-write, un approccio di ottimizzazione ben noto (che ho anche insegnato più volte nelle mie conferenze C ++). Dopodiché, il trucco a lettura zero non funziona più per quella pagina e questo è il motivo per cui le prestazioni erano molto più basse dopo aver inserito il ciclo init – apparentemente ridondante.

calloc è generalmente malloc+memset a 0

In genere è leggermente meglio usare malloc+memset esplicito, specialmente quando si fa qualcosa del tipo:

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

Questo è meglio perché sizeof(Item) è noto al compilatore in fase di compilazione e il compilatore nella maggior parte dei casi lo sostituirà con le migliori istruzioni possibili per azzerare la memoria. D’altra parte se memset sta accadendo in calloc , la dimensione del parametro dell’allocazione non è compilata nel codice calloc e spesso viene chiamato real memset , che di solito contiene il codice per fare riempire byte per byte fino al limite lungo, di ciclo per riempire la memoria in sizeof(long) pezzi e infine byte per byte riempire lo spazio rimanente. Anche se l’allocatore è abbastanza intelligente da chiamare alcuni aligned_memset , sarà comunque un ciclo generico.

Un’eccezione degna di nota potrebbe essere quando si esegue malloc / calloc di un grosso blocco di memoria (alcuni power_of_two kilobyte), nel qual caso l’allocazione può essere effettuata direttamente dal kernel. Poiché i kernel del sistema operativo in genere azzerano tutta la memoria che danno via per motivi di sicurezza, calloc abbastanza intelligente potrebbe semplicemente restituirlo con un ulteriore azzeramento. Ancora una volta – se stai solo assegnando qualcosa che sai essere piccolo, potresti stare meglio con malloc + memset dal punto di vista delle prestazioni.

malloc() alloca il blocco di memoria di una determinata dimensione (in byte) e restituisce un puntatore all’inizio del blocco.

 void *malloc(size_t size); 

malloc() non inizializza la memoria allocata.

calloc() alloca la memoria e inizializza anche l’allocazione della memoria a tutti i bit zero.

 void *calloc(size_t num, size_t size); 

Differenza 1: malloc () di solito alloca il blocco di memoria ed è un segmento di memoria inizializzato. calloc () alloca il blocco di memoria e inizializza tutto il blocco di memoria su 0.

Differenza 2: se si considera la syntax di malloc (), ci vorrà solo 1 argomento. Considera il seguente esempio qui sotto:

data_type ptr = (cast_type *) malloc (sizeof (data_type) * no_of_blocks);

Es .: Se si desidera allocare 10 blocchi di memoria per il tipo int,

  int *ptr = (int *) malloc(sizeof(int) * 10 ); 

Se si considera la syntax calloc (), saranno necessari 2 argomenti. Considera il seguente esempio qui sotto:

data_type ptr = (cast_type *) calloc (no_of_blocks, (sizeof (data_type)));

Es: se si desidera allocare 10 blocchi di memoria per il tipo int e inizializzare tutto ciò su ZERO,

  int *ptr = (int *) calloc(10, (sizeof(int))); 

Somiglianza:

Sia malloc () che calloc () restituiranno void * di default se non sono casted.!

Ci sono due differenze.
Innanzitutto, è nel numero di argomenti. malloc() accetta un singolo argomento (memoria richiesta in byte), mentre calloc() richiede due argomenti.
In secondo luogo, malloc() non inizializza la memoria allocata, mentre calloc() inizializza la memoria allocata su ZERO.

  • calloc() alloca un’area di memoria, la lunghezza sarà il prodotto dei suoi parametri. calloc riempie la memoria con ZERO e restituisce un puntatore al primo byte. Se non riesce a localizzare abbastanza spazio, restituisce un puntatore NULL .

Sintassi: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block); cioè ptr_var=(type *)calloc(n,s);

  • malloc() assegna un singolo blocco di memoria di REQUSTED SIZE e restituisce un puntatore al primo byte. Se non riesce a individuare quantità di memoria requsted, restituisce un puntatore nullo.

Sintassi: ptr_var=(cast_type *)malloc(Size_in_bytes); La funzione malloc() accetta un argomento, che è il numero di byte da allocare, mentre la funzione calloc() accetta due argomenti, uno è il numero di elementi e l’altro è il numero di byte da allocare per ciascuno di questi elementi . Inoltre, calloc() inizializza lo spazio allocato a zero, mentre malloc() no.

La funzione calloc() dichiarata nell’intestazione offre un paio di vantaggi rispetto alla funzione malloc() .

  1. Alloca la memoria come un numero di elementi di una determinata dimensione, e
  2. Inizializza la memoria allocata in modo che tutti i bit siano zero.

Una differenza non ancora menzionata: limite di dimensioni

void *malloc(size_t size) può solo allocare fino a SIZE_MAX .

void *calloc(size_t nmemb, size_t size); può allocare circa SIZE_MAX*SIZE_MAX .

Questa capacità non è spesso utilizzata in molte piattaforms con indirizzamento lineare. Tali sistemi limitano calloc() con nmemb * size <= SIZE_MAX .

Considera un tipo di 512 byte chiamato disk_sector e il codice vuole utilizzare molti settori. Qui, il codice può utilizzare solo fino a SIZE_MAX/sizeof disk_sector settori SIZE_MAX/sizeof disk_sector .

 size_t count = SIZE_MAX/sizeof disk_sector; disk_sector *p = malloc(count * sizeof *p); 

Considera quanto segue che consente un'allocazione ancora più grande.

 size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX) disk_sector *p = calloc(count, sizeof *p); 

Ora, se un tale sistema può fornire una tale allocazione di grandi dimensioni è un'altra questione. La maggior parte di oggi non lo farà. Eppure è accaduto per molti anni quando SIZE_MAX era 65535. Data la legge di Moore , si sospetta che si verificherà intorno al 2030 con alcuni modelli di memoria con SIZE_MAX == 4294967295 e pool di memoria nei 100 GByte.

Le principali differenze tra malloc e calloc sono:

  1. malloc sta per allocazione di memoria mentre calloc sta per allocazione contigua .
  2. malloc accetta un solo argomento , la dimensione del blocco mentre calloc prende due argomenti , il numero di blocchi da allocare e la dimensione di ogni blocco.

    ptr = (cast-type *) malloc (byte-size) // malloc

    ptr = (cast-type *) calloc (no di blocchi, dimensione del blocco); // calloc

  3. malloc non esegue l’inizializzazione della memoria e tutti gli indirizzi memorizzano il valore della spazzatura mentre calloc esegue l’inizializzazione della memoria e gli indirizzi vengono inizializzati su valori Zero o Null .

malloc (): assegna la dimensione richiesta di byte e restituisce un primo byte del puntatore dello spazio allocato

calloc (): alloca lo spazio per gli elementi di un array, inizializza a zero e quindi restituisce un puntatore alla memoria

Il nome malloc e calloc () sono funzioni di libreria che allocano la memoria in modo dinamico.
Significa che la memoria viene allocata durante il runtime (esecuzione del programma) dal segmento heap.

Inizializzazione: malloc () alloca un blocco di memoria di una determinata dimensione (in byte) e restituisce un puntatore all’inizio del blocco.

 > malloc() doesn't initialize the allocated memory. If we try to access the content of memory block then we'll get garbage values. void * > malloc( size_t size ); > calloc() allocates the memory and also initializes the allocates memory block to zero. If we try to access the content of these blocks then we'll get 0. > void * calloc( size_t num, size_t size ); 

Un numero di argomenti: Diversamente da malloc (), calloc () accetta due argomenti: 1) Un numero di blocchi da assegnare. 2) Dimensione di ogni blocco.

Più importante :

Sarebbe meglio usare malloc su calloc, a meno che non vogliamo l’inizializzazione zero perché malloc è più veloce di calloc. Quindi se vogliamo solo copiare qualcosa o fare qualcosa che non richiede il riempimento dei blocchi con zeri, allora malloc sarebbe una scelta migliore.

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

assegna solo n bytes di memoria senza alcuna inizializzazione (cioè quei byte di memoria conterranno tutti i valori garbage).

 char *ptr = (char *) malloc (n, sizeof(char)); 

Tuttavia, il metodo calloc() in c fa l’inizializzazione come valore 0 per tutti i byte di memoria occupati in aggiunta alla funzione che fa malloc() .

Ma a parte questo, c’è una differenza molto importante . Mentre chiama malloc(x) assegna la memoria (uguale a x blocchi) e restituisce il puntatore al primo byte allocato. Tuttavia, non verificherà se vengono allocati esattamente x blocchi di memoria. Ciò porterà al caso di overflow della memoria. Tuttavia calloc() verifica la dimensione dell’allocazione. Se fallisce nell’assegnazione della memoria o nella verifica dei byte allocati, restituirà semplicemente null.

malloc() e calloc() sono funzioni della libreria standard C che consentono l’allocazione dynamic della memoria, il che significa che entrambi consentono l’allocazione della memoria durante il runtime.

I loro prototipi sono i seguenti:

 void *malloc( size_t n); void *calloc( size_t n, size_t t) 

Ci sono principalmente due differenze tra i due:

  • Comportamento: malloc() assegna un blocco di memoria, senza inizializzarlo, e la lettura del contenuto da questo blocco produrrà valori obsoleti. calloc() , d’altra parte, assegna un blocco di memoria e lo inizializza a zero, e ovviamente leggendo il contenuto di questo blocco si otterranno degli zeri.

  • Sintassi: malloc() accetta 1 argomento (la dimensione da allocare) e calloc() accetta due argomenti (numero di blocchi da allocare e dimensione di ciascun blocco).

Il valore restituito da entrambi è un puntatore al blocco di memoria assegnato, se ha esito positivo. In caso contrario, verrà restituito NULL che indica l’errore di allocazione della memoria.

Esempio:

 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 stessa funzionalità di calloc() può essere ottenuta usando malloc() e 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)); 

Si noti che malloc() è preferibilmente utilizzato su calloc() poiché è più veloce. Se si desidera inizializzare a zero i valori, utilizzare calloc() .

Il malloc () accetta un singolo argomento, mentre calloc () takess due.

In secondo luogo, malloc () non inizializza la memoria allocata, mentre calloc () inizializza la memoria allocata su ZERO. Sia il malloc che il calloc sono usati in linguaggio C per l’allocazione dynamic della memoria e ottengono blocchi di memoria dynamicmente.