Questa è una vecchia versione del documento!
Indice
Esercitazione allocazione dinamica
Esercizio 1: Sequenze e VLA
Realizzare un programma C che legge e memorizza in un VLA una sequenza di double di lunghezza non nota a tempo di compilazione (ma nota all'utente a tempo di esecuzione). Richiedere all'utente di specificare la lunghezza prima di immettere la sequenza.
Esercizio 2: Sequenze e malloc()
Modificare la soluzione all'esercizio 1 in modo da utilizzare la funzione malloc()
per allocare l'array dopo aver letto la lunghezza.
Verificare la corretta allocazione e gestire gli errori.
Esercizio 3: Allocazioni in grossi blocchi
Eseguire il seguente programma C
#include <stdio.h> #include <stdlib.h> #define SIZE 10000000000 int main (void) { double * h; h = malloc(SIZE*sizeof(double)); if ( h == NULL ) { perror("malloc"); exit(EXIT_FAILURE); } printf("Allocato h = %p\n",(void *) h); return 0; }
cosa succede ? Cercate di capire che cosa succede quando va in esecuzione perror()
andando a verificare il manuale (sezione 3 man 3 perror
)
Esercizio 4: realloc()
Modificare la soluzione all'esercizio 2 in modo da utilizzare la funzione relloc()
per fare crescere dinamicamente l'array senza richiedere la lunghezza della sequenza.
Verificare la corretta allocazione e gestire gli errori.
Esercizio 5: Effetti collaterali indesiderati
Se ho una variabile intera “int i”, posso modificarne il valore con una funzione che riceve un puntatore “&i” (di tipo int *) alla cella di memoria di “i”.
Allo stesso modo, se ho un array di interi “int * a”, posso modificarne il valore, ovvero creare un nuovo array a cui 'a' e' un riferimento con una funzione che riceve un puntatore &a
(di tipo int
) alla cella di memoria di a.
Le due funzioni
array1() e
array2() qui sotto tentano di fare proprio questo. Tuttavia, dopo aver inizializzato l'array B notiamo che il contenuto dell'array A e' cambiato.
Qual'e' il motivo di questo comportamento? (suggerimento: guardare le slides su VLA)
<code>
#include <stdio.h>
questa funzione riceve un puntatore ad un array di interi, ed ha il compito di creare un array in qu
void array1(int c);
questa funzione si comporta come array1 ma crea un array differente
void array2(int c);
int main(){
int * aA; array A
int * aB; array B
array1(&aA);
printf(“array A: %d, %d, %d \n”,aA[0],aA[1],aA[2]);
array2(&aB);
printf(“array B: %d, %d, %d \n”,aB[0],aB[1],aB[2]);
ma nel frattempo, cosa e' successo all'array A?
printf(“array A: %d, %d, %d \n”,aA[0],aA[1],aA[2]);
return 0;
}
void array1(int c){
int n = 3;
avendo usato a[n], la dimensione non e' nota a tempo di compilazione
quindi non possiamo utilizzare la costruzione con valore letterale “a[n] = {1,2,3}”
int a[n];
a[0] = 1;
a[1] = 2;
a[2] = 3;
*c = a;
}
void array2(int c){
int n = 3;
int a[n];
a[0] = 4;
a[1] = 5;
a[2] = 6;
*c = a;
}
</code>
Correggere il codice in modo che le funzioni array1() e array2() allochino i rispettivi array sullo heap con la funzione “malloc()”, e venga quindi evitato l'effetto collaterale di B su A.
===== Esercizio 5: Funzione di allocazione/deallocazione di matrici =====
Le matrici possono essere rappresentate come array di puntatori a righe.
Si richiede di implementare le funzioni per la creazione e la deallocazione di matrici
nxm
di double. In particolare, la funzione
<code>
/ crea una matrice di double rappresentata come array di puntatori a righe
\param n numero di righe
\param m numero di colonne
\retval NULL se si e' verificato un errore
\retval p puntatore alla matrice allocata altrimenti
*/
double mat_new (unsigned n, unsigned m);
</code>
crea una matrice con n righe ed m colonne e ne restituisce il puntatore. E
<code>
/ libera la memoria occupata da una matrice di double rappresentata come array di puntatori a righe
\param a puntatore alla matrice da deallocare
\param n numero di righe
*/
void mat_free (double a, unsigned n);
</code>
Sviluppare un opportuno main che testa che l'allocazione e la deallocazione siano stata effettuata correttamente, anche in caso di errori in corso d'opera.