Nel linguaggio C, gli array sono una struttura di base per memorizzare un insieme ordinato di elementi dello stesso tipo. Offrono un accesso rapido per indice e sono strettamente legati al funzionamento dei puntatori. Gli array possono essere dichiarati staticamente, automaticamente (nello stack) o dinamicamente (nel heap). Il tipo di allocazione influisce sulla durata di vita dell'array, sulla sua accessibilità da diverse parti del codice e sui requisiti per la gestione della memoria.
Storia della questione
Il C originale permetteva di definire solo array statici e automatici, ma con l'emergere dell'allocazione dinamica di memoria (funzioni malloc, calloc, free) sono emersi nuovi schemi di progettazione che hanno aumentato la flessibilità del codice.
Problema
Gli sviluppatori spesso commettono errori con le dimensioni, il tempo di vita e la pulizia degli array, portando a perdite di memoria, condizioni di competizione e corruzione della memoria.
Soluzione
Una scelta attenta del tipo di archiviazione in base al compito, un attento monitoraggio dell'inizializzazione e un tempestivo rilascio della memoria per gli array dinamici.
Esempio di codice:
#include <stdio.h> #include <stdlib.h> int main() { // Automatico (nello stack) int auto_arr[5] = {1,2,3,4,5}; // Statico (vive finché la programma è in esecuzione) static int static_arr[5]; // Dinamico (nel heap) int *dyn_arr = malloc(5 * sizeof(int)); for (int i = 0; i < 5; i++) dyn_arr[i] = i * 2; // Utilizzo for (int i = 0; i < 5; i++) printf("%d ", dyn_arr[i]); printf(" "); free(dyn_arr); return 0; }
Caratteristiche chiave:
Si può conoscere la dimensione di un array dinamico tramite sizeof?
No, sizeof(ptr) per un array dinamico restituirà la dimensione di un puntatore, non dell'array. È necessario memorizzare manualmente la dimensione o utilizzare una variabile separata.
int* arr = malloc(10 * sizeof(int)); printf("%zu ", sizeof(arr)); // Dimensione del puntatore, non dell'array
Cosa succede quando si va oltre i limiti dell'array?
Nel linguaggio C non c'è una verifica automatica dei limiti dell'array: l'accesso oltre i limiti porta a comportamenti indefiniti. Gli errori vengono rilevati solo durante l'esecuzione o potrebbero non essere rilevati affatto.
È possibile restituire un array locale (automatico) da una funzione?
No! Un array dichiarato all'interno di una funzione viene eliminato dopo il suo completamento. Restituire un tale array porta ad un accesso a memoria già liberata.
int* create_wrong_array() { int arr[10]; return arr; // Errore: restituisce un puntatore allo stack }
Uno sviluppatore crea un array nello stack e restituisce un puntatore ad esso da una funzione. Il programma a volte va in crash o restituisce dati spazzatura.
Vantaggi:
Svantaggi:
Utilizzo dell'allocazione dinamica con passaggio della dimensione insieme al puntatore, pulizia della memoria tramite free. Tutti i casi di liberazione della memoria sono verificati attraverso test unitari.
Vantaggi:
Svantaggi: