10 aprile 2025
Le strutture sono molto utili per definire… strutture dati.
Per esempio si possono definire array dinamici, liste concatenate, alberi, pile, code…
Gli array in C sono molto limitati, infatti dobbiamo gestire la loro lunghezza a mano…
Si può creare una struttura che contenga un array e la sua lunghezza:
Adesso si può passare la struttura come argomento di una funzione:
void stampa_array(IntArray a) {
for (int i = 0; i < a.length; i++) {
printf("%d ", a.array[i]);
}
printf("\n");
}
Si nota subito che non abbiamo più bisogno di passare la lunghezza dell’array come argomento.
int append(IntArray *a, int value) {
if (a->length < MAX) {
a->array[a->length] = value;
a->length++;
return 0;
}
return 1;
}
append
prende come argomento un puntatore a IntArray
e un intero da aggiungere all’array, l’array è passato by reference perché i suoi campi vengono modificati->
, che è una forma abbreviata di (*p).membro
Per esercizio si implementino le funzioni:
int get(IntArray a, int index)
che restituisce l’elemento in posizione index
, int insert(IntArray *a, int index, int value)
che inserisce l’elemento value
in posizione index
, int remove(IntArray *a, int index)
che rimuove l’elemento in posizione index
.
Scarica il main dell’esercizio
Consiglio
Si noti che le funzioni insert
e remove
possono fallire se l’array è pieno o vuoto, rispettivamente, inoltre è necessario spostare tutti gli elementi dell’array.
L’implementazione che abbiamo visto ha due grossi problemi:
IntArray
funziona solo con array di interi, per fare array di float, char, ecc. bisogna creare ogni volta una nuova strutturaLe strutture dati in C hanno dimensione fissa. Infatti gli array vengono inizializzati con un valore costante.
Esistono però dei comandi che permettono di allocare dinamicamente zone di memoria, permettendo di fare strutture che crescono o si rimpiccioliscono durante l’esecuzione del programma.
Le operazioni per gestire la memoria dinamica si trovano nella libreria stdlib.h
e sono:
malloc
(memory allocation): alloca una zona di memoria di una certa dimensionecalloc
(clear allocation): alloca una zona di memoria di una certa dimensione e la inizializza a 0realloc
(reallocate): cambia la dimensione di una zona di memoria già allocatamalloc
, calloc
e realloc
restituiscono un puntatore a void, che è un puntatore generico.
Questo puntatore non fa riferimento a un certo tipo di dato, ma solo a un indirizzo di memoria.
malloc
void* malloc(size_t size);
Supponendo di voler creare un array di interi di dimensione variabile, c’è bisogno di creare un puntatore ad interi e poi assegnargli l’indirizzo della nuova zona di memoria:
La funzione malloc
accetta come argomento il numero di byte da allocare. L’esempio crea 10 cellette di memoria, ciascuna grande quanto un intero (4 byte).
calloc
void* calloc(size_t num, size_t size);
L’effetto di questo codice è lo stesso del precedente (con la malloc), ma con tutti i membri dell’array inizializzati a 0.
realloc
void* realloc(void* ptr, size_t size);
Questa funzione cambia la dimensione di uno spazio allocato dinamicamente.
L’argomento ptr
deve essere un puntatore ottenuto da una funzione ..alloc, altrimenti porta a comportamento non definito.
I dati già presenti nella zona di memoria vengono mantenuti.
Quando si usa la memoria dinamica, è importante controllare che l’allocazione sia andata a buon fine.
Se malloc
, calloc
o realloc
non riescono a trovare spazio in memoria, restituiscono NULL
.
NULL
è una costante che rappresenta un puntatore all’indirizzo 0x0
. NULL
è definito in stdlib.h
.
malloc
, calloc
, realloc
free
void free(void* ptr);
ptr
dopo l’esecuzione di free
continua a puntare alla stessa zona di memoria, ma il contenuto di quella zona non è più garantito, si chiama dangling pointerptr
il valore NULL
(oppure una nuova memoria)Un array dinamico è un array la cui dimensione può cambiare durante l’esecuzione del programma.
Per implementare un array dinamico si può usare una struttura che contiene un puntatore all’array e la sua lunghezza:
ArrayList
Il nuovo tipo ArrayList
ha tre membri:
array
è un puntatore ad interi, che punta all’array dinamicocapacity
è la dimensione massima dell’arraylength
è il numero di elementi attualmente presenti nell’arrayQuando length raggiunge capacity, bisogna riallocare la memoria per l’array, aumentando la sua dimensione.
L’implementazione classica della lista concatenata in C è:
Dato il file con il main e i prototipi delle funzioni, implementare:
Dati e Algoritmi