C/Gestione della memoria: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Riga 17:
 
== Funzioni di allocazione dinamica ==
L'allocazione dinamica della memoria avviene generalmente attraverso la funzione '''malloc()''', oppure '''calloc()''', definite nella libreria standard '''stdlib.h'''. Se queste riescono a eseguire l'operazione, restituiscono il puntatore alla memoria allocata, altrimenti restituiscono il valore NULL.
 
'''void *malloc''' ('''size_t''' ''dimensione'');
 
'''void *calloc''' ('''size_t''' quantitànumero, '''size_t''' dimensione);
 
La differenza tra le due funzioni sta nel fatto che la prima, '''malloc()''', viene utilizzata per allocare un'area di memoria di una certa ''dimensione,'' (espressa generalmente in byte), mentre la seconda, '''calloc()''', permette di indicare unail quantità''numero'' di elementi e si presta per l'allocazione di array. (che, proprio per questa caratteristica di essere a dimensione variabile, si dicono array dinamici)
 
Dovendo utilizzare queste funzioni per allocare della memoria, è necessario conoscere la dimensione dei tipi primitivi di dati, ma per evitare incompatibilità conviene farsi aiutare dall'operatore '''sizeof()'''.
 
Il valore restituito da queste funzioni è di tipo void * cioè una specie di puntatore neutro, indipendente dal tipo di dati da utilizzare. Per questo, in linea di principio, prima di assegnare a un puntatore il risultato dell'esecuzione di queste funzioni di allocazione, è opportuno eseguire un cast (conversione) al tipo di dato desiderato.
 
Il valore restituito da queste funzioni è di tipo void * cioè una specie di puntatore neutro, indipendente dal tipo di dati da utilizzare. Per questo, in linea di principio, prima di assegnare a un puntatore il risultato dell'esecuzione di queste funzioni di allocazione, è opportuno eseguire un cast.
<source lang="c">
int *pi = NULL;
/* ... */
pi = (int *) malloc (sizeof (int)); // pi è un puntatore a interi
 
if (pi != NULL)
{
// Il puntatore è valido e allora procede.
/* ... */
}
else
{
// La memoria non è stata allocata e si fa qualcosa
// di alternativo.
/* ... */
}
</source>
Come si può osservare dall'esempio, il cast viene eseguito con la notazione (int *) che richiedeesegue la conversione esplicita in un puntatore a '''int'''. Lo standard C non richiede l'utilizzo di questo cast, quindi l'esempio si può ridurre al modo seguente:
 
...
Line 51 ⟶ 52:
...
 
La memoria allocata dinamicamente deve essere liberata in modo esplicito quando non serve più. Per questo si utilizza la funzione '''free()''' che richiede semplicemente il puntatore alla memoria precedentemente allocata e non restituisce alcunché.
 
'''void free''' ('''void''' *puntatorep); // p punta alla memoria allocata in precedenza
 
È necessario evitare di deallocare più di una volta la stessa area di memoria, perché ciò potrebbe provocare effetti imprevedibili.
Line 77 ⟶ 78:
</source>
=== realloc() ===
Lo standard prevede una funzione ulteriore, per la riallocazione di memoria: '''realloc()'''. Questa funzione si usa per ridefinire l'area di memoria con una dimensione differente (proprio in virtù del fatto che stiamo usando la memoria "dinamica):
 
'''void *realloc''' ('''void''' *''puntatore'', '''size_t''' ''dimensione'');
 
In pratica, la riallocazione deve rendere disponibili gli stessi contenuti già utilizzati, salvo la possibilità che questi siano stati ridotti nella parte terminale. Se invece la dimensione richiesta nella riallocazione è maggiore di quella precedente, lo spazio aggiunto può contenere dati casuali. Il funzionamento di '''realloc()''''''Testo in grassetto''' non è garantito, pertanto occorre verificare nuovamente, dopo il suo utilizzo, che il puntatore ottenuto sia ancora valido.
 
[[Categoria:C|Gestione della memoria]]