2010-09-24 5 views

risposta

12

malloc alloca memoria. I contenuti della memoria vengono lasciati così come sono (riempiti con qualsiasi cosa ci fosse prima).

calloc alloca la memoria e imposta il suo contenuto su tutti zeri.

realloc modifica la dimensione di un blocco di memoria assegnato esistente o copia il contenuto di un blocco di memoria esistente in un blocco appena assegnato della dimensione richiesta, quindi rilascia il vecchio blocco.

Ovviamente, realloc è una situazione di caso speciale. Se non si dispone di un vecchio blocco di memoria per ridimensionare (o copiare e deallocare), non c'è motivo di usarlo. Il motivo per cui lo standard malloc viene utilizzato al posto di calloc è perché c'è un costo di runtime per impostare la memoria su tutti zero e se si prevede di riempire immediatamente la memoria con dati utili (come è comune), non c'è motivo prima di azzerarlo.

Queste funzioni sono tutte standard e si comportano in modo affidabile tra i compilatori.

+2

'calloc' è particolarmente utile per l'assegnazione di matrici di strutture, poiché richiede 2 arg: 'calloc (num_of_items, size_of_item)'. È più lavoro riempire un array di dati utili (come dice Tyler), quindi c'è un buon argomento a favore del costo extra per inizializzare la memoria a un valore noto (zero). –

+2

'calloc' ha anche il vantaggio di eseguire la moltiplicazione per te, in modo che su un'implementazione non bacata controllerà e fallirà l'overflow. –

+0

Non hai menzionato 'strdup' o' asprintf', che alloca anche memoria. – abelenky

1

calloc è probabile che solo implementato come qualcosa di simile a:

void * calloc(size_t nmemb, size_t size) { 
     size_t len = nmemb * size); 
     void * ptr = malloc(len); 
     if (ptr) { 
      return memset(ptr, 0, len); 
     } 
     return ptr; 
} 

Quindi aggiunge solo un moltiplicano prima e una chiara dopo il malloc.

malloc potrebbe essere (ma probabilmente non è mai) implementato come:

void * malloc(size_t size) { 
     return realloc(NULL, size); 
} 

perché si può passare realloc un puntatore NULL come il puntatore del precedente, ma malloc è più probabile che non implementato così perché sarebbe rallentare tutti i mallocs e poiché realloc utilizza probabilmente malloc.

La cosa principale da sapere su realloc è che è spesso in grado di determinare la dimensione effettiva del blocco di memoria restituita da una qualsiasi delle routine di allocazione dell'heap e vedere se il blocco è già sufficientemente grande o in alcuni casi se sarebbe meglio cercare di ridurre il blocco o spostarlo.

void realloc(void * ptr, size_t size) { 
    size_t alen = MALLOC_LENGTH_OF(ptr); // this just stands for some method of determining 
            // the size of the block that was allocated, and could 
            // be looking it up in a table or looking at a place 
            // several bytes before the pointer, or some other 
            // implementation specific thing 
    if (0 == size) { 
     free(ptr); 
     return NULL; 
    } 
    if (alen >= size) { 
     return ptr; // big enough, and not worrying about it being too big 
    } 
    void new_ptr = malloc(size); // since I said that malloc most likely isn't 
           // implemented using realloc using malloc here is ok 
    if (new_ptr && ptr) { 
     memcpy(new_ptr, ptr, alen); 
    } 
    free(ptr); 
    return new_ptr; 
} 

Malloc è usato di più perché è il più semplice. I programmatori possono spesso rendere le loro allocazioni abbastanza grandi per cominciare da non doversi preoccupare di ridimensionarle con realloc, e molto spesso la cancellazione della memoria non è necessaria.

Ci sono diversi comportamenti tra le diverse librerie e si possono anche collegare programmi con altre versioni solo per ottenere questo comportamento diverso senza (di solito senza modificare il compilatore).

Alcune librerie malloc sono per il debug e il rilevamento degli errori. Altri potrebbero offrire prestazioni migliori.Alcuni sono ottimizzati per allocare memoria per diversi thread contemporaneamente e per evitare che i vari thread debbano bloccare l'intero heap per eseguire un'allocazione o gratuitamente.

Tutti però dovrebbero fornire la stessa semantica dal punto di vista delle applicazioni.

+0

votare giù per usare le parentesi graffe di inizio sulla stessa linea del blocco!(non proprio così) – Firoso

+0

@Firoso: facendo ciò, _diff_ produce risultati migliori confrontando le versioni e riduce il codice. Dal momento che uso anche le parentesi graffe attorno ai blocchi di una linea, è davvero utile metterli sulla stessa riga del codice di apertura del blocco. – nategoose

+0

se si fa riferimento all'opzione diff -p, credo che l'euristica sia che una riga contiene un nome di funzione se ha lettere nella colonna 1. – ninjalj

3

Oltre a quelli che si stanno citano (alcuni sono estensioni):

  • variabili nello stack vengono anche assegnati dinamicamente. La ricorsione è un modo per assegnarlo e usarlo.
  • C99 ha array di lunghezza variabile (come menzionato BlueRaja).
  • Su alcuni sistemi è persino disponibile una chiamata alloca che consente di allocare blocchi di lunghezza variabile nello stack frame.
  • POSIX ha mappatura di segmenti di memoria e file, con combinazioni di shm_open o open e mmap.
  • SysV IPC ha shmget ecc chiama
+0

Windows dispone anche di modi per condividere la memoria tra i processi e mappare i file in memoria. – RBerteig

2

Un metodo per allocare memoria che non è stato menzionato è alloca(size_t size) che riserva dimensione byte di memoria su stack frame corrente e automaticamente libera nuovamente la memoria quando si lascia la pila telaio.

0

malloc: indica che hai ptr = (int *) malloc (10); Questo alloca 10 byte contigui di spazio di memoria e l'indirizzo del primo byte è memorizzato nella variabile puntatore ptr. La memoria allocata ora contiene il valore spazzatura.
Quindi se io varia da 0 a 3 scanf ("% d", ptr + i); memorizza 4 numeri interi in 4 posizioni contigue. ptr ha l'indirizzo del 1 ° intero, ptr + 1 ha l'indirizzo del 2 ° numero e così via. Quindi printf ("% d", atstrick (ptr + i)); stamperà i valori corrispondenti. A differenza della memoria allocata per variabili e matrici, l'allocazione dinamica non ha alcun nome associato ad essa. Come visto sopra.

calloc: È simile a malloc tranne due differenza: 1. Dichiarazione: ptr = (int *) calloc (5, sizeof (int)); Qui abbiamo due argomenti, 5 non è di blocchi allocati e il secondo argomento è uguale a 4 byte. Questo è equivalente a ptr = (int *) malloc (5 * sizeof (int)); 2.In memoria calloc allocata inizialmente non è garbage, ma è 0. Sia malloc che calloc restituiscono NULL se non c'è sufficiente memoria disponibile nell'heap.