Storicamente, i puntatori sono diventati la base del lavoro con la memoria nel linguaggio C e offrono un meccanismo flessibile per un accesso efficiente agli elementi dell'array e alle strutture dinamiche. Tuttavia, la sintassi e la semantica dei puntatori agli array e degli array di puntatori spesso creano confusione.
Problema: i programmatori principianti spesso confondono puntatore all'array (pointer to array) e array di puntatori (array of pointers), il che porta a un utilizzo improprio della memoria, errori nella trasmissione dei parametri e errori di sintassi difficili da costruire.
Soluzione:
Esempio di dichiarazione e utilizzo:
// Puntatore a un array di 10 int: int (*p)[10]; int arr[10]; p = &arr; // Array di 10 puntatori a int int *ap[10]; for (int i = 0; i < 10; ++i) { ap[i] = &arr[i]; } // Come ottenere un elemento tramite un puntatore a un array: (*p)[2] = 5; // terzo elemento arr // Come ottenere un valore utilizzando un array di puntatori: *ap[2] = 8; // terzo elemento arr tramite ap
Caratteristiche chiave:
**int p[10] e int (p)[10] sono uguali?
No. int *p[10] è un array di 10 puntatori a int. int (*p)[10] è un puntatore a un array di 10 int. Grande confusione si verifica senza parentesi!
Esempio di codice:
int arr[10]; int *p[10]; // array di puntatori int (*q)[10] = &arr; // puntatore a un array
*È possibile assegnare liberamente un puntatore normale a int a una variabile di tipo int (p)[10]?
No. Un normale int * punta a un singolo elemento, mentre int (*p)[10] punta a un array di 10 interi; i tipi non sono compatibili senza un esplicito cast.
Come passare correttamente un array bidimensionale a una funzione?
È necessario specificare esplicitamente la dimensione della seconda dimensione:
void foo(int a[][4], int n); // array n righe di 4 elementi
oppure utilizzare un puntatore a un array:
void bar(int (*a)[4], int n);
Un ingegnere dichiara una variabile come int *p[10], cerca di assegnarle &arr, dove arr è int arr[10] e cerca di accedere come a un array, riceve un errore di compilazione o un comportamento non valido.
Vantaggi:
Svantaggi:
Un sviluppatore usa attentamente le parentesi: int (*p)[10], capisce chiaramente la differenza, passa correttamente gli array alle funzioni, usa typedef per semplificare le dichiarazioni.
Vantaggi:
Svantaggi: