Puntatori e Array
I puntatori condividono numerose caratteristiche con gli array. Mentre i puntatori codificano la posizione di un singolo oggetto in memoria, gli array codificano la posizione e la lunghezza di una serie di oggetti contigui.
Il Decadimento degli Array (Array Decay)
Section titled “Il Decadimento degli Array (Array Decay)”Al primo pretesto utile, un array “decade” (decay) in un puntatore. Quando un array decade, perde l’informazione sulla sua lunghezza e si converte in un puntatore al suo primo elemento.
int key_to_the_universe[]{ 3, 6, 9 };int* key_ptr = key_to_the_universe; // key_ptr punta a 3. Nessuna operazione & necessaria!Questo comportamento è onnipresente nelle API in stile C. Molto spesso passerai array a funzioni fornendo due parametri:
- Un puntatore al primo elemento (l’array decaduto).
- La lunghezza dell’array.
Aritmetica dei Puntatori
Section titled “Aritmetica dei Puntatori”Per ottenere l’indirizzo dell’n-esimo elemento di un array, hai due opzioni:
- Usare le parentesi quadre:
&array[n] - Usare l’aritmetica dei puntatori:
array + n
Quando sommi o sottrai interi ai puntatori, il compilatore calcola automaticamente il corretto offset in byte basandosi sulla dimensione del tipo puntato. Ad esempio, se sommi 4 a un puntatore a uint64_t (che occupa 8 byte), il compilatore aumenterà l’indirizzo di memoria di 32 byte (4 x 8).
I Puntatori sono Pericolosi (Buffer Overflow)
Section titled “I Puntatori sono Pericolosi (Buffer Overflow)”L’aritmetica dei puntatori e l’indicizzazione offrono una libertà totale, ma come recita il proverbio, da un grande potere derivano grandi responsabilità.
Puoi accedere ad elementi arbitrari in memoria. Questa libertà ti consente astrazioni di basso livello formidabili (essenziali nel system programming), ma un piccolo errore può portare a difetti catastrofici: i cosiddetti Buffer Overflow.
Scrivere in zone di memoria che non ti appartengono, come fa lower[7] = 'g', provoca in C++ un Comportamento Indefinito (Undefined Behavior). Il tuo programma potrebbe ignorarlo, crashare per una violazione di accesso (Segmentation Fault), o peggio ancora, aprire una vulnerabilità di sicurezza permettendo a malintenzionati di eseguire codice malevolo. Difetti di questo tipo possono risultare estremamente difficili da scovare, dato che il crash o il comportamento errato possono manifestarsi molto più tardi durante l’esecuzione del programma.