Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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.
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 ) ; } }
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.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
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 ;
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