Allocazione dinamica della memoria
• La creazione di nuove variabili a run time (tipo new in Java) viene effettuata in C
utilizzando le funzioni di libreria standard che permettono l’allocazione dinamica di porzioni contigue di memoria
– malloc, calloc, realloc – #include <stdlib.h>
Con queste primitive è possibile creare
dinamicamente variabili e array di dimensione
Array dinamici -- malloc( )
• Vediamo come creare dinamicamente un array di 10 posizioni
int * a; /*conterrà il puntatore al primo elemento dell’array*/
a = malloc(10*sizeof(int));
heap 40 byte
Punta allʼindirizzo iniziale della nuova
area allocata 100
96
Array dinamici -- malloc( ) (2)
• Vediamo come creare dinamicamente un array di 10 posizioni
int * a; /*conterrà il puntatore al primo elemento dell’array*/
a = malloc(10*sizeof(int));
if (a == NULL) printf(“fallimento!\n”);
Se malloc non riesce ad allocare
lʼarea di memoria richiesta restituisce NULL (verificare…)
Array dinamici -- malloc( ) (3)
• Vediamo come creare dinamicamente un array di 10 posizioni
int * a; /*conterrà il puntatore al primo elemento dell’array*/
a = malloc(10*sizeof(int));
if (a == NULL) printf(“fallimento!\n”);
else {
a[4] = 345;
… }
Lʼarray si può accedere con i consueti heap
40 byte
100 96
Array dinamici -- malloc( ) (4)
• malloc non inizializza la memoria a 0!
– Possiamo inizializzarla esplicitamente o – usare calloc
int * a; /*conterrà il puntatore al primo elemento dell’array*/
a = calloc(10*sizeof(int));
If (a == NULL) printf(“fallimento!\n”);
else {
a[4] = 345;
Array dinamici -- realloc( )
• realloc modifica la lunghezza di un’area allocata precedentemente
int * a, * b; /*puntatori al primo elemento dell’array*/
a = malloc(10*sizeof(int));
…
b = realloc(a,20*sizeof(int));
/* adesso b punta ad un array di 20 elementi */
Array dinamici -- realloc( ) (2)
• Meglio usare sempre due puntatori diversi (a,b) !
– Altrimenti in caso di fallimento NULL sovrascrive il
vecchio puntatore
Array dinamici -- free( )
• Lo spazio allocato sullo heap non viene deallocato all’uscita delle funzioni
• La deallocazione deve essere richiesta esplicitamente usando free
int * a;
a = malloc(10*sizeof(int));
…
free(a);
/* se qua accedo di nuovo ad a può succedere di tutto */
tipo puntatore generico: void *
• non si può dereferenziare
• è necessario un cast prima di manipolare la variabile puntata
– Es.
void * c;
int a;
c = &a;
*c = 5; /* scorretto*/
*(int *)c = 5; /* corretto*/
tipo puntatore generico: void * (2)
• Serve a scrivere funzioni ‘polimorfe’ in una maniera un po’ brutale
• Esempio
– il tipo della malloc è
void * malloc (unsigned int size);
– quando scrivo
int * a;
a = malloc(10*sizeof(int));
viene effettuato un cast implicito a (int *)
tipo puntatore generico: void * (3)
• Tipi delle altre funzioni di allocazione e deallocazione
void * calloc (unsigned int size);
void * realloc (void * ptr,
unsigned int size);
void free (void * ptr);
I puntatori a funzione
• Consideriamo la funzione
int somma (int x, int y) { return x + y;
}
– se proviamo ad eseguire
printf(“%p”, somma);
otteniamo un valore esadecimale che
rappresenta un indirizzo legale del nostro programma
– ??????????????????????????
I puntatori a funzione (2)
• Consideriamo la funzione
int somma (int x, int y) { return x + y;
}
Codice compilato
di somma IND
somma è un puntatore costante
I puntatori a funzione (3)
• Consideriamo la funzione
int somma (int x, int y) { return x + y;
}
/* variabile di tipo funzione (int,int)->int */
int (*fun) (int,int);
int a;
fun = somma;
a = fun(3,5);
I puntatori a funzione (4)
• Consideriamo la funzione
int somma (int x, int y) { return x + y;
}
/* variabile di tipo funzione (int,int)->int */
int (*fun) (int,int);
int a;
fun = somma;
Ma a che serve
????????????
I puntatori a funzione (5)
• Serve a definire funzioni che prendono come argomenti altre funzioni (di ordine superiore)
void map (int (*fun) (int), int x[ ], int l) { for(i = 0; i < l; i++) x[i] = fun(x[i]);
}
è un iteratore che applica la funzione fun a
tutti gli elementi dell’array x
I puntatori a funzione (6)
• Esempio di uso della map
int piu_uno (int x) { return x+1;}
int quad (int x) { return x*x;}
…
int a[3] = {3,4,5};
map(piu_uno,a,3); /* somma uno a tutti gli elementi */
map(quad,a,2); /* eleva al quadrato i primi due elementi */
Argomenti della linea di comando
• Gli argomenti della linea di comando sono accessibili all’interno della funzione main
– il SO li inserisce sullo stack prima di attivare il processo
– il formato in cui sono resi disponibili è fisso
int main (int argc, char * argv[ ]) { …
}
Numero di argomenti nella linea di comando
Array di puntatori agli argomenti
(ciascuno è una stringa, tipo char*)
Argomenti della linea di comando (2)
• Esempio
%> a.out una stringa per a.out
5 argc
argv p e r \O
a . o u t \O
s t r i n g u n a \O
a \O argv[0]
Argomenti della linea di comando (3)
• Esempio : Schema di programma che stampa gli argomenti sulla linea di comando
int main (int argc, char * argv[ ]) { …
for(i = 0; i < argc; i++)
printf(“arg %d: %s”, i, argv[i]);
… }
Array multidimensionali come array di puntatori
• Vogliamo permettere la definizione di
funzioni su array multidimensionali che non dipendono dal valore delle dimensioni
successive alla prima
int sum_mat (int ** MAT,
int n, int m) { …
}
Nome della matrice
Numero di righe, colonne
Array multidimensionali come array di puntatori (2)
• Vogliamo accedere agli elementi dell’array usando la solita notazione [-][-]
int sum_mat (int ** MAT,
int n, int m) { …
MAT[i][j] = …;
}
*(MAT + i*m + j) Il compilatore
dovrebbe conoscere il legame fra questi due oggetti
Array multidimensionali come array di puntatori (3)
• Una alternativa: abbandonare l’allocazione contigua per righe
MAT
7 2 6 2 1 2 3 4
4 6 1 2 MAT[0]
MAT[1]
3 5 7 9 MAT[2]
MAT[3]
MAT[4]
MAT[2][2]
Array multidimensionali come array di puntatori (4)
• Una alternativa: vediamo i tipi ...
MAT
7 2 6 2 1 2 3 4
4 6 1 2
4 5 1 2 MAT[0]
MAT[1]
3 5 7 9 MAT[2]
MAT[3]
MAT[4]
MAT[2][2]
int**
int*[5]
int[4]
Array multidimensionali come array di puntatori (5)
• Una alternativa: in memoria non ho più aree contigue ...
MAT 1 2 3 4
4 6 1 2 MAT[0]
3 5 7 9
40 44 48 52
40 120140400 4
70 74 78 82 86
120 124 128 132 140 144 148 152 indirizzo
valore
Array multidimensionali come array di puntatori (6)
• Perché funziona?
int sum_mat (int ** MAT,
int n, int m) { …
MAT[i][j] = …;
}
*(*(MAT + i) + j) Questo legame non interessa più!
Array multidimensionali come array di puntatori (7)
• Funzione di allocazione
int ** mat_new(unsigned int m, unsigned int n) {
int i, ** a, errore = FALSE;
a = malloc(m*sizeof(int*));
if (a == NULL) return NULL;
for(i = 0; (i < m) && (!errore); i++) { a[i] = malloc(n*sizeof(int));
if (a[i] == NULL) errore = TRUE;
}
if (errore) /* gestione errori */
Array multidimensionali come array di puntatori (8)
• Funzione di deallocazione
void mat_free(int ** a, unsigned int m)
{
int i;
/* dealloco tutte le righe */
for(i = 0; i < m; i++) free(a[i]);
/* dealloco l’array dei puntatori alle righe */
free(a);