Free in C

Free in C

In questa lezione studieremo la funzione free che serve a rilasciare la memoria precedentemente allocata in maniera dinamica con le funzioni malloc, calloc o realloc.

Il prototipo della funzione free in C è:

void free(void *);

Quindi la funzione ha come argomento il puntatore all’inizio dell’area di memoria precedentemente allocata, che adesso si vuole rendere disponibile perché non più utilizzata. La funzione inoltre non ha alcun valore di ritorno.


Esempio di utilizzo di free in C

Facciamo un semplice esempio per capire come utilizzare al funzione.

Innanzitutto dichiariamo un puntatore a double, dopo con la funzione malloc allochiamo un’area di memoria per contenere un array di elementi double.

Dopo controlliamo che il puntatore non abbia valore NULL per poter proseguire nel programma.

Poi assegniamo dei valori e li visualizziamo con la funzione printf.

Infine liberiamo la memoria utilizzando la funzione free in C, a cui passiamo come argomento il puntatore.

Ecco dunque il listato completo:

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
	/*dichiariamo un puntatore a double*/
  	double * a;
 
	/*riserviamo un'area di memoria per un array di 5000 elementi double*/
 	a=(double *) malloc(5000*sizeof(double)); 

 	if(a==NULL) {
	   printf("\n allocazione fallita !");
    	exit(0);
	}
	
  	a[2000]=123.45;
  	a[99]=-12.895;
  	
  	/*stampo i valori*/
 	printf("I valori inseriti sono: %lf %lf", a[2000], a[99]);
	
	/*libero l'area di memoria */
 	free(a);

return 0; 
}

Dopo che un puntatore è stato passato come argomento alla funzione free, diventa un dangling pointer, cioè un puntatore pendente. Infatti esso fa riferimento a un’area di memoria non più disponibile.

Bisogna prestare attenzione a non de-allocare più volte la stessa area di memoria in quanto potrebbero esserci degli effetti imprevedibili.

Alcuni link utili

Indice tutorial linguaggio C

Media per riga e per colonna

Somma elementi diagonale principale di una matrice

Come sommare gli elementi della cornice esterna

Come sommare due matrici

Sommare dei numeri di una matrice

Matrice trasposta

Prodotto tra matrici

Ricerca elementi in una matrice

Inserire dati in una matrice

Tavola pitagorica in C

Array multidimensionali

Programma sui triangoli in C

Media dei numeri in un array

Array con numeri random

Quick sort in C

Selection sort in C

Merge sort in C

Insertion Sort in C

Garbage collection

Garbage collection

Con il termine di garbage collection, letteralmente “raccolta dei rifiuti” si intende la liberazione delle porzioni di memoria allocate, ma non più utilizzate. Le aree di memoria liberate tornano così ad essere nuovamente disponibili.

Con il sistema Gargabe Collector intendiamo dunque quel meccanismo a runtime che si occupa di ricercare le aree di memoria non più utilizzate e di renderle nuovamente utilizzabili.

Questo meccanismo è utile quando si dichiarano le variabili in modo dinamico, in quanto non si conosce esattamente l’inizio o la fine.

Nelle variabili statiche invece si conosce esattamente il tempo di vita e può essere determinato all’atto di compilazione del codice sorgente.

Garbage collection in C

In C non esiste un vero e proprio Gargabe Collector che verifichi quando un oggetto può essere de-allocato. Quindi deve essere il programmatore a decidere quando effettuare la de-allocazione.

In molti linguaggio di programmazione invece, come ad esempio Java e Phyton, il sistema del garbage collection è direttamente integrato nell’ambiente di esecuzione.

Quindi, come facilmente intuibile, uno dei vantaggi consiste nel fatto che il programmatore non si deve preoccupare di richiedere o rilasciare aree di memoria. Ma uno degli svantaggi principali è che si consumano maggiormente risorse di calcolo.

Abbiamo introdotto il concetto di garbage collection in C, nella prossima lezione parleremo della funzione free, utile per liberare la memoria precedentemente allocata.

Alcuni link utili

Indice tutorial linguaggio C

Realizzare un menù di scelta in C

Strutture complesse in C

Typedef struct C

Media per riga e per colonna

Somma elementi diagonale principale di una matrice

Come sommare gli elementi della cornice esterna

Come sommare due matrici

Matrice trasposta

Prodotto tra matrici

Ricerca elementi in una matrice

Inserire dati in una matrice

Tavola pitagorica in C

Array multidimensionali

Media dei numeri in un array

Array con numeri random

Quick sort in C

Selection sort in C

Merge sort in C

Insertion Sort in C


Realloc

Realloc

In questa lezione studieremo la funzione realloc in C, per modificare le aree precedentemente allocate anche in una fase successiva.

Abbiamo già studiato infatti le funzioni malloc e calloc che permettono di allocare la memoria dinamicamente.

Il prototipo di realloc è:

void *realloc(void *, size_t);

Dove, il primo argomento rappresenta il puntatore all’inizio dell’area di memoria che si vuole dimensionare, mentre il secondo indica la nuova dimensione da assegnare al blocco di memoria.

Se il nuovo blocco di memoria è più grande di quello precedente allora i dati rimarranno inalterati, in caso contrario invece i dati saranno eliminati.

Anche in questo caso il valore di ritorno è di tipo void, quindi per far si che punti a tipi diversi occorre effettuare un’operazione di cast, così come abbiamo già visto per malloc e calloc.

La funzione realloc si può anche chiamare più volte sullo stesso puntatore.

Inoltre ricordiamo che se il puntatore è NULL si comporta allo stesso modo di malloc().

Esempio di utilizzo di realloc

Innanzitutto utilizziamo malloc per allocare un array di 10 interi, ma quando assegniamo a[10]=13; o ad esempio a[18]=-120; stiamo commento un errore. Occorre infatti fare la riallocazione utilizzando la funzione realloc.

#include <stdio.h>
#include <stdlib.h>

int main () {
	int *a; 

	/*allochiamo un array di 10 interi*/
	a=malloc(10*sizeof(int));
        
        if(a==NULL) {
	   printf("\nAllocazione fallita!");
    	   exit(0);
	}	

	/*allocazioni corrette*/
	a[2]=-5;
	a[7]=22;
	
	/*allocazioni non corrette perchè sono fuori dalla zona assegnata con la malloc*/
	a[10]=13;
	a[18]=-120;
	
	/* occorre prima fare una riallocazione se vogliamo ad esempio contenere 20 interi*/
  	a=realloc(a, 20*sizeof(int));
  	
  	/*adesso si può arrivare sino ad a[19]*/
  	a[10]=13;
	a[18]=-120;
	
  	printf("a[2]=%d a[7]=%d a[10]=%d a[18]=%d\n", a[2], a[7], a[10], a[18]);
 	
 	return 0; 
} 

Chiaramente questo è solo un semplice esempio di utilizzo della funzione realloc in C, più avanti faremo altri esempi.

Alcuni link utili

Indice tutorial linguaggio C

Realizzare un menù di scelta in C

Strutture complesse in C

Esercizio sulle struct in C

Typedef struct C

Media per riga e per colonna

Somma elementi diagonale principale di una matrice

Come sommare gli elementi della cornice esterna

Come sommare due matrici

Sommare dei numeri di una matrice

Matrice trasposta

Prodotto tra matrici

Ricerca elementi in una matrice

Inserire dati in una matrice

Tavola pitagorica in C

Array multidimensionali

Programma sui triangoli in C

Media dei numeri in un array

Array con numeri random

Quick sort in C

Selection sort in C

Merge sort in C

Insertion Sort in C


Calloc

Calloc

In questa lezione parleremo della funzione calloc in C, che è molto utile per l’allocazione dinamica di array.

Nell’esempio precedente abbiamo utilizzato malloc per allocare un array, che è comunque una funzione molto utilizzata anche per tale scopo.

Malloc non inizializza la memoria a zero, dobbiamo farlo esplicitamente, oppure utilizziamo la funzione calloc. Infatti la funzione calloc inizializza ogni byte del blocco di memoria a zero.

La sintassi della funzione calloc in C è la seguente:

void *calloc(size_t num, size_t dim)

Quindi la funzione prevede due argomenti, il primo rappresenta il numero di elementi da allocare mentre il secondo la quantità di memoria per ogni elemento.

Se ad esempio vogliamo allocare un vettore di n elementi di tipo intero, possiamo utilizzare calloc:

int *a;
a=(int *) calloc(n,sizeof(int));

Il puntatore punterà al primo elemento di un vettore di n elementi interi.

Possiamo anche utilizzare malloc in questo modo:

int *a;
a=(int *) malloc(n*sizeof(int));

Sia calloc che malloc restituiscono NULL se non riescono ad allocare la quantità di memoria richiesta, ad esempio perché esaurita.


Esempio di utilizzo di calloc in C

Riproponiamo l’esempio del calcolo della media che abbiamo visto nella lezione precedente, al fine di comparare i due metodi.

Ecco dunque il listato completo che fa uso della funzione calloc, per allocare dinamicamente la memoria.

#include <stdio.h>
#include <stdlib.h>

int main () {
	int *a, i, n; 
	float media;
	
	a=(int *) calloc(n,sizeof(int));
	
	printf("Quanti valori?" );
	scanf("%d", &n);

	for(i=0;i<n; i++)    {    
		printf("Elemento %d: ", i+1);   
		scanf("%d",  &a[i]) ;   
 	} 

 	media=0; 
 	for(i=0;i<n;i++)    
 		media=media+a[i];
 	
 	media/=n;
 		printf ("La  media e':  %.2f" ,  media ); 
 		
 	return 0; 
} 

Anche qui si potrebbe effettuare un test sul contenuto del puntatore, in modo tale che, se l’allocazione non avviene correttamente (per esempio se non abbiamo sufficiente spazio di memoria), compaia un messaggio di avviso.

Chiaramente questo è solo un semplice esempio di utilizzo della funzione calloc in C per allocare la memoria dinamicamente.

Alcuni link utili

Media per riga e per colonna

Somma elementi diagonale principale di una matrice

Come sommare gli elementi della cornice esterna

Come sommare due matrici

Sommare dei numeri di una matrice

Matrice trasposta

Prodotto tra matrici

Ricerca elementi in una matrice

Inserire dati in una matrice

Tavola pitagorica in C

Array multidimensionali

Programma sui triangoli in C

Media dei numeri in un array

Array con numeri random

Quick sort in C

Selection sort in C

Merge sort in C

Insertion Sort in C

Malloc in C

Malloc in C

Malloc() – In questa lezione utilizzeremo la funzione malloc in C per l’allocazione dinamica della memoria.

Quindi proponiamo un semplice programma che prende in input un array di 10 elementi e calcoli la media degli elementi.

Dapprima vediamo le possibili soluzioni senza l’utilizzo della funzione malloc in C.

Ecco dunque una possibile soluzione.

#include <stdio.h>
#define N 10

int main () {
	int a[N], i;
	float media;

	for(i=0;i<N; i++)    {    
		printf("Elemento %d: ", i+1);   
		scanf("%d",  &a[i]) ;   
 	} 

 	media=0; 
 	for(i=0;i<N;i++)    
 		media+=a[i];
 	
 	media/=N;
 	printf("La  media e':  %d",  media ); 
 		
 	return 0; 
} 

Pertanto in questo esempio è possibile effettuare la media solo dei 10 elementi precedentemente stabiliti.

Se volessimo ad esempio effettuare la media di 20 elementi allora dovremmo modificare la costante N e ricompilare il programma.

Si potrebbe allora chiedere all’utente di quanti numeri voler effettuare la media, per avere una soluzione più flessibile.

        ....
        int n;
	
	printf("Quanti valori?" );
	scanf("%d ", &n);
        int a[n];
        ....

Ma questa soluzione non è corretta, in quanto n è noto solo a tempo di esecuzione (ovvero dopo che l’utente lo inserisce da tastiera e lo leggiamo tramite scanf).

Allora una delle possibili soluzioni è il sovradimensionamento dell’array, soluzione che in definitiva abbiamo utilizzato finora.

Magari facendo un controllo dell’input per permettere valori di n compresi tra 1 e 1000.

Ecco dunque la soluzione sempre senza l’utilizzo della funzione malloc in C.

#include <stdio.h>

#define MAX 1000

int main () {
	int  a[MAX], i, media; 
	int n;
	
	do { 
		printf("Quanti valori?");
		scanf("%d", &n);
	} while (n<0 && n>1000);


	for(i=0;i<n; i++)    {    
		printf("Elemento %d: ", i+1);   
		scanf("%d",  &a[i]) ;   
 	} 


 	media=0; 
 	for(i=0;i<n;i++)    
 		media+=a[i];
 	
 	media/=n;
 	printf("La  media e':  %d",  media); 
 		
 	return 0; 
} 

Chiaramente, come potete intuire, il problema è lo spreco di memoria.


Allocazione dinamica – utilizzo di malloc in C

Quindi quale approccio più efficiente potremmo utilizzare?

Sicuramente l’allocazione dinamica della memoria con l’utilizzo della funzione malloc, che ci permette di utilizzare un vettore formato da un numero di elementi uguale a quelli da elaborare.

Ecco dunque il listato completo con l’utilizzo di malloc in C.

#include <stdio.h>
#include <stdlib.h>


int main () {
	int *a, i, n; 
	float media;
	
	a=(int *) malloc(sizeof(int));
	
	printf("Quanti valori?" );
	scanf("%d", &n);

	for(i=0;i<n; i++)  {    
		printf("Elemento %d: ", i+1);   
		scanf("%d",  &a[i] ) ;   
 	} 

 	media=0; 
 	for(i=0;i<n;i++)    
 		media+=a[i];
 	
 	media/=n;
 	printf("La  media e':  %.2f" ,  media ); 
 		
 	return 0; 
} 

In questo modo alloco la quantità necessaria esattamente per elaborare n interi: a=(int *) malloc(sizeof(int)).

Anche in questo esempio potremmo prima controllare se l’allocazione avviene correttamente, controllando che a sia diverso da NULL.

Ancora non ho introdotto le altre funzioni free, realloc e calloc. Presto ne faremo uso.

Chiaramente questo era solo un semplice esempio d’utilizzo della funzione malloc in C.

Alcuni link utili

Media per riga e per colonna

Somma elementi diagonale principale di una matrice

Come sommare gli elementi della cornice esterna

Come sommare due matrici

Sommare dei numeri di una matrice

Matrice trasposta

Prodotto tra matrici

Ricerca elementi in una matrice

Inserire dati in una matrice

Tavola pitagorica in C

Array multidimensionali

Programma sui triangoli in C

Media dei numeri in un array

Array con numeri random

Quick sort in C

Selection sort in C

Merge sort in C

Insertion Sort in C