You are on page 1of 13

LAllocazione Dinamica della Memoria

Maurizio Palesi DIITUniversit di Catania Viale Andrea Doria 6, 95125 Catania mpalesi@diit.unict.it http://www.diit.unict.it/users/mpalesi
Sommario Questo documento tratta lallocazione dinamica della memoria in C. Verr evidenziato come, alcune volte, lutilizzo di strutture dati di tipo statico non sono opportune in certi scenari applicativi. Saranno descritte in dettaglio le funzioni C per la gestione dinamica della memoria e presentati diversi esempi.

Indice
1 Introduzione 2 Perch Allocare Dinamicamente? 2.1 Sovradimensionamento . . 2.2 Allocazione Dinamica . .

3 Gestione Dinamica della Memoria 3.1 calloc() e malloc() 1 3.2 free() . . . . . . . . . . 3.3 realloc() . . . . . . . 2 4 Matrici Dinamiche 3 4 5 Esercizi

5 5 6 6 6 7

1 Introduzione
La scelta delle appropriate strutture dati di fondamentale importanza per la risoluzione di un certo problema almeno tanto quanto un buon programma di manipolazione. Fin qui ci siamo occupati di strutture dati sia di tipo scalare (tipo intero, reale, carattere) sia di tipo strutturato (stringhe, vettori, e strutture). A ciascuna di esse abbiamo associato le relative rappresentazioni interne previste dal C. Le variabili corrispondenti ai tipi suddetti non possono mutare le loro caratteristiche in fase di esecuzione e pertanto sono dette statiche. Vogliamo occuparci ora di un altro tipo di variabili: quelle dinamiche cio le variabili che possono essere create e/o accresciute in fase di esecuzione.

2 Perch Allocare Dinamicamente?


Il lettore potrebbe chiedersi qual la necessit di utilizzare lallocazione statica piuttosto che quella dinamica. Si consideri per esempio il seguente frammento di codice per il calcolo della media degli elementi di un vettore. Una prima versione potrebbe essere: # define N 10 main ( ) { i n t v [N ] , i , somma , media ; / inserimento dati / f o r ( i = 0 ; i <N ; i ++) { p r i n t f ( " I n s e r i s c i e l e m e n t o %d esim o : " ) ; s c a n f ( "%d " , & v [ i ] ) ; } / c a l c o l o d e l l a media e v i s u a l i z z a z i o n e somma = 0 ; f o r ( i = 0 ; i <N ; i ++) somma = somma + v [ i ] ; media = somma / N; p r i n t f ( " La media : % d " , media ) ; } Il problema in questo caso che tale codice effettua la media esclusivamente di N valori. Se si volesse per esempio calcolare la media di 20 numeri piuttosto che di 10 occorrerebbe modicare N: # define N 20 e ricompilare il programma. Una soluzione per per rendere il programma pi essibile sarebbe quella di chiedere allutente di inserire il numero di elementi di cui calcolare la media e quindi utilizzare tale valore in luogo di N. Chiaramente una soluzione del tipo: ... i n t num ; p r i n t f ( " Di q u a n t i v a l o r i v u o i f a r e l a media ? " ) ; s c a n f ( "%d " , & num ) ; i n t v [ num ] ; ... non corretta in C visto che la dichiarazione di un vettore richiede la conoscenza del numero di elementi a tempo di compilazione. Nel suddetto frammento di codice, infatti,

il valore della variabile num non noto a tempo di compilazione ma soltanto a tempo di esecuzione (in questo caso dopo lesecuzione della scanf). Nelle sottosezioni successive presentiamo due diverse soluzioni a questo problema. La prima sovradimensiona il vettore mentre la seconda fa uso dellallocazione dinamica della memoria.

2.1

Sovradimensionamento

Una possibile soluzione potrebbe essere quella di sovradimensionare il vettore in questo modo: # d e f i n e MAXDIM 1 0 0 main ( ) { i n t v [MAXDIM ] , num , i , somma , media ; p r i n t f ( " Di q u a n t i v a l o r i v u o i f a r e l a media ? " ) ; s c a n f ( "%d " , & num ) ; / c o n t r o l l o s e ho l e r i s o r s e n e c e s s a r i e / / per memorizzare t u t t i i d a t i / i f ( num > MAXDIM) p r i n t f ( " i l v e t t o r e pu c o n t e n e r e a l massimo %d v a l o r i " , MAXDIM ) ; else { / inserimento dati / f o r ( i = 0 ; i <num ; i ++) { p r i n t f ( " I n s e r i s c i e l e m e n t o %d esim o : " ) ; s c a n f ( "%d " , & v [ i ] ) ; } / c a l c o l o d e l l a media e v i s u a l i z z a z i o n e somma = 0 ; f o r ( i = 0 ; i <num ; i ++) somma = somma + v [ i ] ; media = somma / num ; p r i n t f ( " La media : % d " , media ) ; } }

Il problema di questo approccio per lo spreco di memoria.

2.2

Allocazione Dinamica

Un approccio pi efciente dal punto di vista dellutilizzazione della risorsa memoria sarebbe quello di utilizzare sempre un vettore formato da un numero di elementi esattamente uguale a quelli da elaborare. main ( ) { i n t v , num , i , somma , media ; p r i n t f ( " Di q u a n t i v a l o r i v u o i f a r e l a media ? " ) ; s c a n f ( "%d " , & num ) ; / a l l o c o una q u a n t i t d i memoria n e c e s s a r i a / p e r m e m o r i z z a r e e s a t t a m e n t e num i n t e r i / i l puntatore v punter esattamente / a l l i n i z i o d i q u e s t a area v = ( i n t ) m a l l o c ( num s i z e o f ( i n t ) ) ; / inserimento dati / f o r ( i = 0 ; i <num ; i ++) { p r i n t f ( " I n s e r i s c i e l e m e n t o %d esim o : " ) ; s c a n f ( "%d " , & v [ i ] ) ; } / c a l c o l o d e l l a media e v i s u a l i z z a z i o n e somma = 0 ; f o r ( i = 0 ; i <um ; i ++) somma = somma + v [ i ] ; media = somma / num ; p r i n t f ( " La media : % d " , media ) ; / ora p o s s o l i b e r a r e l a r e a d i memoria / precedentemente allocata free (v ); }

/ / / /

/ /

Le funzioni malloc() , free() e diverse altre saranno discusse nella sezione successiva.

3 Gestione Dinamica della Memoria


In questa sezione descriveremo in dettaglio le funzioni messe a disposizione dalla libreria standard C per la gestione dinamica della memoria. Le principali sono quattro: malloc(), calloc() , free(), ralloc() e sono accessibili includendo il le header stdlib.h : #include <stdlib.h> malloc() e calloc() allocano un blocco di memoria, free() libera un blocco di memoria precedentemente allocato e realloc() modica le dimensioni di un blocco di memoria precedentemente allocato.

3.1

calloc() e malloc()

Il prototipo delle funzioni malloc e calloc il seguente: void c a l l o c ( i n t num_elementi , i n t dim_elemento ) ; void malloc ( d i m _ t o t a l e ) ; calloc() alloca memoria per un vettore di num_elementi elementi di dim_elemento bytes ciascuno e restituisce un puntatore alla memoria allocata. Inoltre inizializza ogni byte di tale blocco di memoria a zero. malloc() alloca dim_totale bytes di memoria e restituisce un puntatore a tale blocco. In questo caso la memoria non inizializzata a nessun valore. Per determinare la dimensione in byte di un tipo di dato possibile utilizzare la funzione sizeof() . Quindi, per esempio, per allocare un vettore di n elementi di tipo intero basta fare: int v ; v = ( int ) calloc (n , sizeof ( int ) ) ; Il puntatore v punter al primo elemento di un vettore di n elementi interi. Si noti che stato utilizzato il casting per assegnare il puntatore restituito da calloc a v. Infatti calloc restituisce un void* mentre v un int*. Analogamente si pu utilizzare la funzione malloc per ottenere lo stesso risultato: int v ; v = ( i n t ) malloc ( n s i z e o f ( i n t ) ) ; In questo caso occorre determinare il numero totale di bytes da allocare che pari al numero di elementi del vettore per la dimensione in bytes del generico elemento. In questo caso poich il vettore contiene interi, la dimensione del generico elemento sizeof(int) .

Sia calloc() che malloc() restituiscono NULL se non riescono ad allocare la quantit di memoria richiesta.

3.2

free()

Il prototipo della funzione free() : void f r e e ( void p t r ) ; Essa rilascia (libera o dealloca) lo spazio di memoria puntato da ptr il cui valore proveniva da una precedente malloc() o calloc() o realloc() . Se ptr NULL nessuna operazione viene eseguita.

3.3

realloc()

Il prototipo della funzione realloc() : void r e a l l o c ( void p t r , i n t d i m _ t o t a l e ) ; Essa modica la dimensione di un blocco di memoria puntato da ptr a dim_totale bytes. Se ptr NULL, linvocazione equivalente ad una malloc(dim_totale). Se dim_totale 0, linvocazione equivalente ad una free(ptr) . Naturalmente il valore di ptr deve provenire da una precedente invocazione di malloc() o calloc() o realloc() .

4 Matrici Dinamiche
Possiamo rappresentare una matrice come un vettore di vettori. Cio lelemento -esimo di un vettore un vettore che rappresenta le colonne della matrice. Per costruire una matrice dinamica di r righe e c colonne baster eseguire le seguenti due operazioni: 1. Allocare dinamicamente un vettore di r puntatori (vettore delle righe). 2. Per ogni riga allocare un vettore di c elementi del tipo base considerato (vettore colonne). La Figura 1 mostra la rappresentazione graca di una matrice dinamica. Per esempio il seguente frammento di codice denisce ed alloca una matrice dinamica di interi di r righe e c colonne. { i n t m a t r i c e , i ; / a l l o c o i l v e t t o r e d e l l e r i g h e . Ogni e l e m e n t o / d i q u e s t o v e t t o r e un p u n t a t o r e m a t r i c e = ( i n t ) m a l l o c ( r s i z e o f ( i n t ) ) ;

/ /

0 0 1 2 3 4

1 2 3 4 5 6 7

Figura 1: Rappresentazione di una matrice dinamica vista come un vettore di puntatori.


/ per ogni riga al l oco l e colonne / f o r ( i = 0 ; i < r ; i ++) m at r i ce [ i ] = ( i n t ) malloc ( c s i z e o f ( i n t ) ) ; } Per disallocare una matrice dinamica, invece, occorre procedere alla rovescia: prima si disallocano tutte le colonne quindi si disalloca il vettore dei puntatori alle colonne. { / per ogni riga d i s a l l o c o l e colonne / f o r ( i = 0 ; i < r ; i ++) free ( matrice [ i ] ) ; / disa lloco i l verrore de lle righe free ( matrice ) ; }

5 Esercizi
Esercizio 5.1 () Calcolare la media degli elementi di una sequenza di valori double inseriti dallutente. La ne della sequenza identicata dal numero 0.0. Utilizzare vettori dinamici.

Risoluzione # i n c l u d e < s t d i o . h> # i n c l u d e < s t d l i b . h> v o i d main ( ) { d ou b le v e t t o r e , e l e m e n t o , somma , media ; int i , j , fine ; v e t t o r e = NULL ; / inserimento dati / i = 0; fine = 0; while ( ! f i n e ) { p r i n t f ( " I n s e r i s c i un e l e m e n t o ( 0 p e r f i n i r e ) : " ) ; s c a n f ( "% l f " , & e l e m e n t o ) ; i f ( elemento = = 0 . 0 ) fine = 1; else { / aum ento d i 1 l a d i m e n s i o n e d e l v e t t o r e / v e t t o r e = ( d ou b le ) r e a l l o c ( v e t t o r e , ( i + 1 ) s i z e o f ( d ou b le ) ) ; v e t t o r e [ i ] = elemento ; i ++; } } / c a l c o l o e stam pa d e l l a media somma = 0 . 0 ; f o r ( j = 0 ; j < i ; j ++) somma + = v e t t o r e [ j ] ;

media = somma / i ; p r i n t f ( " La media : % l f \ n " , media ) ; / dellocazione del ve tt or e free ( vettore );

Esercizio 5.2 () Calcolare la trasposta di una matrice di interi allocata dinamicamente. Risoluzione # i n c l u d e < s t d i o . h> # i n c l u d e < s t d l i b . h> v o i d main ( ) { i n t m a t r i c e , t r a s p o s t a ; int righe , colonne , r , c ; p r i n t f ( " Q uante r i g h e ha l a m a t r i c e : " ) ; s c a n f ( "%d " , & r i g h e ) ; p r i n t f ( " Q uante c o l o n n e ha l a m a t r i c e : " ) ; s c a n f ( "%d " , & c o l o n n e ) ; / allocazione della matrice / m a t r i c e = ( i n t ) m a l l o c ( r i g h e s i z e o f ( i n t ) ) ; f o r ( r = 0 ; r < r i g h e ; r ++) m at r i ce [ r ] = ( i n t ) malloc ( colonne s i z e o f ( i n t ) ) ; / inserimento dati / f o r ( r = 0 ; r < r i g h e ; r ++) f o r ( c = 0 ; c< c o l o n n e ; c ++) { p r i n t f ( " I n s e r i s c i e l e m e n t o d i r i g a %d e c o l o n n a %d : " , r , c ) ; s c a n f ( "%d " , & m a t r i c e [ r ] [ c ] ) ; } / alloco la matrice trasposta / t r a s p o s t a = ( i n t ) m a l l o c ( c o l o n n e s i z e o f ( i n t ) ) ; f o r ( c = 0 ; c< c o l o n n e ; c ++) t r a s p o s t a [ c ] = ( i n t ) malloc ( r i ghe s i z e o f ( i n t ) ) ;

/ calcolo della trasposta / f o r ( r = 0 ; r < r i g h e ; r ++) f o r ( c = 0 ; c< c o l o n n e ; c ++) trasposta [ c ][ r ] = matrice [ r ][ c ]; / stam po l a t r a s p o s t a / p r i n t f ( " La t r a s p o s t a : \ n " ) ; f o r ( c = 0 ; c< c o l o n n e ; c ++) { f o r ( r = 0 ; r < r i g h e ; r ++) p r i n t f ( "%d " , t r a s p o s t a [ c ] [ r ] ) ; pr i n t f ( "\ n" ) ; } / dealloco la matrice / f o r ( r = 0 ; r < r i g h e ; r ++) free ( matrice [ r ] ) ; free ( matrice ) ; / dealloco la trasposta / f o r ( c = 0 ; c< c o l o n n e ; c ++) free ( trasposta [ c ] ); free ( trasposta ); }

Esercizio 5.3 () Calcolare la trasposta di una matrice di interi allocata dinamicamente. Strutturare il programma a funzioni. Risoluzione # i n c l u d e < s t d i o . h> # i n c l u d e < s t d l i b . h> typedef int

TMatrice ;

/ dichiarazione delle funzioni ( prototipi )


10

/ void LeggiRigheColonne ( i n t r , i n t c ) ; TMatrice AllocaMatrice ( in t r , in t c ) ; v o i d I n s e r i m e n t o ( T M a t r i c e mat , i n t r , i n t c ) ; v o i d C a l c o l a T r a s p o s t a ( T M a t r i c e mat , T M a t r i c e t r a s p , i n t r , i n t c ) ; v o i d V i s u a l i z z a M a t r i c e ( T M a t r i c e mat , i n t r , i n t c ) ; v o i d D e a l l o c a M a t r i c e ( T M a t r i c e mat , i n t r ) ; / programma p r i n c i p a l e / v o i d main ( ) { TMatrice m atrice , t r a s p o s t a ; int righe , colonne , r , c ; L e g g i R i g h e C o l o n n e (& r i g h e , & c o l o n n e ) ; matrice = AllocaMatrice ( righe , colonne ) ; Inserimento ( matrice , righe , colonne ) ; p r i n t f ( " Hai i n s e r i t o l a m a t r i c e : \ n " ) ; VisualizzaMatrice ( matrice , righe , colonne ) ; t r a s p o s t a = AllocaMatrice ( colonne , righe ) ; CalcolaTrasposta ( matrice , t r a s p o s t a , righe , colonne ) ; p r i n t f ( " La t r a s p o s t a : \ n " ) ; VisualizzaMatrice ( t r a s p o s t a , colonne , righe ) ; D e a l l o c a M a t r i c e (& m a t r i c e , r i g h e ) ; D e a l l o c a M a t r i c e (& t r a s p o s t a , c o l o n n e ) ; } / definizione delle funzioni




11

void LeggiRigheColonne ( i n t r , i n t c ) { p r i n t f ( " Q uante r i g h e ha l a m a t r i c e : " ) ; s c a n f ( "%d " , r ) ; p r i n t f ( " Q uante c o l o n n e ha l a m a t r i c e : " ) ; s c a n f ( "%d " , c ) ; } TMatrice AllocaMatrice ( in t r , in t c ) { T M a t r i c e mat ; int i ; mat = ( T M a t r i c e ) m a l l o c ( r s i z e o f ( i n t ) ) ; f o r ( i = 0 ; i < r ; i ++) mat [ i ] = ( i n t ) m a l l o c ( c s i z e o f ( i n t ) ) ; r e t u r n mat ; } v o i d I n s e r i m e n t o ( T M a t r i c e mat , i n t r , i n t c ) { int i , j ; f o r ( i = 0 ; i < r ; i ++) f o r ( j = 0 ; j <c ; j ++) { p r i n t f ( " I n s e r i s c i e l e m e n t o d i r i g a %d e c o l o n n a %d : " , i , j ) ; s c a n f ( "%d " , & mat [ i ] [ j ] ) ; } } v o i d C a l c o l a T r a s p o s t a ( T M a t r i c e mat , T M a t r i c e t r a s p , i n t r , i n t c ) { int i , j ; f o r ( i = 0 ; i < r ; i ++) f o r ( j = 0 ; j <c ; j ++) t r a s p [ j ] [ i ] = mat [ i ] [ j ] ; }

12

v o i d V i s u a l i z z a M a t r i c e ( T M a t r i c e mat , i n t r , i n t c ) { int i , j ; f o r ( i = 0 ; i < r ; i ++) { f o r ( j = 0 ; j <c ; j ++) p r i n t f ( "%d " , mat [ i ] [ j ] ) ; pr i n t f ( "\ n" ) ; } } void D e a l l o c a M a t r i c e ( TMatrice { int i ; f o r ( i = 0 ; i < r ; i ++) f r e e ( ( mat ) [ i ] ) ; f r e e ( mat ) ; }

mat , i n t r )

13