Puntatori
I puntatori possono essere pensati come maniglie da applicare alle porte delle
celle di memoria per poter accedere al loro contenuto sia in lettura che in
scrittura, nella pratica una variabile di tipo puntatore contiene l'indirizzo
di una locazione di memoria.
Vediamo alcune esempi di dichiarazione di puntatori:
short* Puntatore1;
Persona* Puntatore3;
double** Puntatore2;
int UnIntero = 5;
int* PuntatoreAInt = &UnIntero;
Il carattere * (asterisco) indica un puntatore, per cui le prime
tre righe dichiarano rispettivamente un puntatore a short int ,
un puntatore a Persona e un puntatore a puntatore a double .
La quinta riga dichiara un puntatore a int e ne esegue l'inizializzazione
mediante l'operatore & (indirizzo di) che serve ad ottere
l'indirizzo della variabile (o di una costante o ancora di una funzione) il
cui nome segue l'operatore. Si osservi che un puntatore a un certo tipo puo`
puntare solo a oggetti di quel tipo, (non e` possibile ad esempio assegnare
l'indirizzo di una variabile di tipo float a un puntatore a
char , come mostra il codice seguente), o meglio in molti casi
e` possibile farlo, ma viene eseguita una coercizione (vedi appendice A):
float Reale = 1.1;
char * Puntatore = &Reale; // Errore!
E` anche possibile assegnare ad un puntatore un valore particolare a indicare
che il puntatore non punta a nulla:
Puntatore = 0;
In luogo di 0 i programmatori C usano la costante NULL , tuttavia
l'uso di NULL comporta alcuni problemi di conversione di tipo;
in C++ il valore 0 viene automaticamente convertito in un puntatore NULL
di dimensione appropriata.
Nelle dichiarazioni di puntatori bisogna prestare attenzione a diversi dettagli
che possono essere meglio apprezzati tramite esempi:
float* Reale, UnAltroReale;
int Intero = 10;
const int* Puntatore = &Intero;
int* const CostantePuntatore = &Intero;
const int* const CostantePuntatoreACostante = &Intero;
La prima dichiarazione contrariamente a quanto si potrebbe pensare non dichiara
due puntatori a float , ma un puntatore a float (Reale)
e una variabile di tipo float (UnAltroReale): * si
applica solo al primo nome che lo segue e quindi il modo corretto di eseguire
quelle dichiarazioni era
float * Reale, * UnAltroReale;
A contribuire all'errore avra` sicuramente influito il fatto che l'asterisco
stava attacato al nome del tipo, tuttavia cambiando stile il problema non si
risolve piu` di tanto. La soluzione migliore solitamente consigliata e` quella
di porre dichiarazioni diverse in righe diverse.
Ritorniamo all'esempio da cui siamo partiti.
La terza riga mostra come dichiarare un puntatore a un intero costante, attenzione
non un puntatore costante; la dichiarazione di un puntatore costante e` mostrata
nella penultima riga. Un puntatore a una costante consente l'accesso all'oggetto
da esso puntato solo in lettura (ma cio` non implica che l'oggetto puntato sia
effettivamente costante), mentre un puntatore costante e` una costante di tipo
puntatore (a ...), non e` quindi possibile modificare l'indirizzo in esso contenuto
e va inizializzato nella dichiarazione. L'ultima riga mostra invece come combinare
puntatori costanti e puntatori a costanti per ottenere costanti di tipo puntatore
a costante (intera, nell'esempio).
Attenzione: anche const , se utilizzato per dichiarare una costante
puntatore, si applica ad un solo nome (come * ) e valgono quindi
le stesse raccomandazioni fatte sopra.
In alcuni casi e` necessario avere puntatori generici, in questi casi il puntatore
va dichiarato void :
void* PuntatoreGenerico;
I puntatori void possono essere inizializzati come un qualsiasi altro puntatore
tipizzato, e a differenza di questi ultimi possono puntare a qualsiasi oggetto
senza riguardo al tipo o al fatto che siano costanti, variabili o funzioni;
tuttavia non e` possibile eseguire sui puntatori void alcune operazioni definite
sui puntatori tipizzati.
|