Il tipo puntatore è introdotto da alcuni linguaggi di programmazione ad alto livello come forma di accesso al livello di astrazione della macchina sottostante.
Non tutti i linguaggi prevedono questa possibilità (ad esempio Fortran, Java).
Una variabile di tipo puntatore può assumere come valore unindirizzo di memoria. In figura la memoria è rappresentata come un vettore di locazioni contigue, ciascuna delle quali può essere riferita attraverso un indirizzo univoco. La locazione contenente la stringa di bit 0011 è l’area di memoria in cui è stata memorizzata una variabile Puntatore. Il suo contenuto 0011 quindi è un indirizzo di memoria che rimanda alla relativa locazione. Questa locazione di memoria, a sua volta, mantiene il dato di valore 1000001.
Non esiste un unico tipo puntatore: più precisamente esiste un insieme di tipi puntatore a seconda del tipo dell’oggetto puntato. Ad esempio:
Nella figura successiva il puntatore all’area di memoria 0011 sarà un puntatore al tipo del dato il cui valore è 100001. Per fissare le idee, se tale dato è di tipo intero la stringa di bit 1000001 sarà interpretata secondo la codifica dei numeri interi e avrà ad esempio valore 65, se invece il dato è di tipo carattere la stessa stringa verrà interpretata come carattere ad esempio il carattere A.
In altre parole non esiste il tipo puntatore in assoluto, ma sempre riferito ad un tipo.
Un puntatore non può contenere un indirizzo qualunque: esiste un vincolo di tipo.
La sintassi traduce tale vincolo consentendo di definire un puntatore ad un certo tipo T.
Il C/C++ prevede puntatori a funzione e puntatori a dati di qualsiasi natura, semplici o strutturati.
In particolare il puntatore viene utilizzato :
T * p;
Esempi:
int * p=o; // ottima abitudine!
char * p;
L’indirizzo della locazione di memoria di una variabile può essere ottenuto attraverso l’operatore unario & (operatore di referenza – “reference”,”address of”):
int x;
int * p;
p=&x;
l’indirizzo di x , &x, e’ assegnato alla variabile p. Si dice che “p punta a x”.
L’operatore di de-referenza * (“content of”) esegue l’operazione inversa dell’operatore &: applicato ad una variabile di tipo puntatore restituisce il valore puntato
int v = *p;
in questa istruzione, e’ assegnato a v il contenuto della memoria a cui p punta (interpretato come numero intero).
Non confondere l’operatore di de-referenza con il costruttore di tipo (T *).
Nell’esempio successivo vengono definite due variabili: una variabile di tipo intero ed una variabile intptr di tipo puntatore intero. La variabile i viene inizializzata al valore 10. La variabile puntatore intptr viene inizialmente inizializzata col valore 0 (in questo momento non punta quindi ad alcuna locazione di memoria) e poi assegnata all’indirizzo di memoria della variabile i, ottenuto applicando l’operatore & alla variabile i.
Le istruzioni successive mostrano l’effetto di tale assegnazione: è possibile visualizzare l’indirizzo di memoria della variabile i visualizzando il valore del puntatore.
Mostra codiceIl linguaggio C++ tratta esplicitamente le espressioni di tipo puntatore; in particolare sono previsti i seguenti operatori:
Definito un puntatore a tipo T
T * p;
il significato di un incremento (decremento) unitario è il seguente:
p=p+1 ⇒ p=p+sizeof(T);
dove sizeof(T) è un operatore che applicato al nome di un tipo restituisce il numero di byte necessario alla rappresentazione in memoria di una variabile di quel tipo.
Pertanto l’incremento è tale che p+1 punta all’area di memoria immediatamente successiva a quella impegnata dall’elemento puntato da p. Questa tecnica è particolarmente utile per i puntatori ad array.
Nell’esempio seguente un vettore di interi viene inizializzato con valori inseriti da tastiera e attraverso un ciclo for vengono visualizzati gli indirizzi di memoria degli elementi del vettore (istruzione cout << (int)&v[i] << endl; ). Gli indirizzi degli elementi del vettore sono ottenuti applicando ad ogni elemento l’operatore &. Si noti che all’indirizzo ritornato da & viene applicata una conversione di tipo, necessaria per ottenere la visualizzazione degli indirizzi in base dieci: in mancanza infatti gli indirizzi verrebbero visualizzati in base esadecimale.
Il programma prosegue mostrando l’utilizzo di un puntatore a tipo intero inizializzato all’indirizzo del primo elemento del vettore. Il puntatore viene usato per stampare il valore del primo elemento del vettore e il suo indirizzo in memoria, poi viene incrmentato di una unità: questo provoca lo spostamento del puntatore sul prossimo elemento del vettore, come mostrato dalle successive istruzioni di stampa.
Nella prossima slide viene mostrato un esempio di esecuzione.
Mostra codiceinserisci 5 elementi di tipo intero:
1
2
3
4
5
sono stati memorizzati ai seguenti indirizzi:
2293592
2293596
2293600
2293604
2293608
valore dell’oggetto puntato da intptr: 1
valore contenuto in intptr: 2293592
valore dell’oggetto puntato da intptr: 2
valore contenuto in intptr: 2293596
Premere un tasto per continuare . . .
1. Strutture e typedef. Record in C/C++: Concetti Base
4. Puntatori a tipi di dato strutturati. Allocazione Dinamica
5. Puntatori: aspetti avanzati
7. Asserzioni
8. Gestione delle eccezioni. Concetti base
9. Programmazione modulare: concetti base
10. Programmazione Modulare: Meccanismi e Strumenti a supporto in C/C++
12. Esercitazione: Strutture Dati Pila e Coda
13. Esercitazione. Strutture Dati: Lista Concatenata
14. Meccanismi di Incapsulamento in C++ Namespaces
15. Programmazione orientata agli oggetti. Introduzione
C. Savy: Da C++ ad UML, McGraw-Hill; Cap. 8, par. 8.1, 8.2.1, 8.2.2, 8.2.3, 8.2.