ProgrammazioneSviluppatore C

Parlaci dettagliatamente del meccanismo di passaggio degli array alle funzioni nel linguaggio C. Quali sono i rischi associati a questo modello e come organizzare correttamente un lavoro sicuro con gli array all'interno delle funzioni?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Nel linguaggio C gli array non vengono passati alle funzioni per valore. Se si passa un array come argomento, alla funzione arriva realmente un puntatore al primo elemento dell'array. Ciò porta a modificare l'array originale, non una sua copia.

Ad esempio:

void fillArray(int arr[], int n) { for (int i = 0; i < n; ++i) arr[i] = i*i; } int main() { int myarr[5]; fillArray(myarr, 5); // ok }

All'interno della funzione:

  • non è possibile conoscere la dimensione dell'array originale tramite sizeof(arr) — questo restituirà la dimensione del puntatore, non dell'array.
  • Si può lavorare solo con quella parte della memoria il cui dimensione è stata passata esplicitamente.

Si può lavorare correttamente e in sicurezza con gli array in questo modo:

  • passate sempre esplicitamente la dimensione dell'array come argomento separato;
  • utilizzate costanti o macro di avvolgimento per le dimensioni;
  • se è necessario proteggere l'array da modifiche, passate const int *arr.

Domanda trabocchetto

Domanda: È possibile sapere la dimensione dell'array originale passato alla funzione tramite l'argomento int arr[] usando sizeof(arr)?

Risposta: No, non è possibile! sizeof(arr) all'interno della funzione restituirà la dimensione del puntatore al tipo (ad esempio, 4 o 8 byte), non la dimensione dell'array.

Esempio:

void f(int arr[]) { printf("%zu ", sizeof(arr)); // dimensione del puntatore, non dell'array! } int main() { int x[10]; f(x); // Di solito stampa 8 (x86_64) o 4 (x86) }

Esempi di errori reali


Storia

In un progetto industriale, le funzioni di copia degli array tentavano di calcolare la lunghezza dell'array al volo, utilizzando sizeof(arr)/sizeof(int) all'interno della funzione. Nella pratica, questo portava a copiare solo una parte dell'array, poiché la dimensione era sempre uguale a 1 (8/8), e i dati venivano sovrascritti in modo imprevedibile.


Storia

In un'applicazione di rete, la funzione di invio dati accettava un buffer come array senza indicare esplicitamente la sua dimensione, il che portava a non inviare l'intero buffer, oppure si leggevano dati spazzatura oltre i confini dell'array, causando errori di trasmissione e instabilità nella connessione.


Storia

Quando si scriveva una libreria per lavorare con le immagini, il programmatore non fornì alla funzione di colorazione un parametro obbligatorio per la dimensione dell'array di immagini. Questo portò a un overflow del buffer e al crash del programma su determinati ingressi, scoperto solo nel test di integrazione su una grande immagine.