IL TIPO PUNTATORI
Introduciamo il concetto di puntatore nei linguaggi di programmazione
utilizzando la metafora variabile = scatola.
Come abbiamo visto le scatole sono caratterizzate dal tipo del contenuto e
da un nome, a questo punto è possibile considerare i nomi delle
scatole come un altro tipo di dato del linguaggio.
Pertanto i nomi delle scatole possono essere immagazzinati in altre
scatole, confrontati per uguaglianza, differenza, .... Inoltre se si
assumesse che hanno una struttura di ordine discreto, è anche
possibile trovare il nome successivo o quello precedente.
I nomi delle scatole sono proprio i valori del tipo puntatori.
Consideriamo la seguente situazione
La scatola (variabile) MARIO contiene il nome di
un'altra scatola
(LUIGI) e
quindi si dice che punta a LUIGI,
da qui nasce il nome di
puntatori.
La scatola MARCO contiene invece il nome nullo (cioè un
elemento speciale che non è il nome di alcuna scatola), o il
puntatore nullo (non punta a
niente).
Operazioni con le scatole di tipo puntatore
- assegnare a MARIO il nome di
PIPPO
MARIO <-PIPPO
non va bene, infatti il nome di una variabile a destra
dell'assegnazione viene interpretato come il contenuto di tale
variabile, è come se ci fosse scritto
MARIO
<- contenuto(PIPPO)
e quindi si avrebbe anche un errore di tipo (tentativo di mettere 0
in una scatola che contiene dei nomi).
Esiste invece un'altra operazione che indica esplicitamente di
considerare un nome di scatola come nome e non come contenuto.
MARIO
<- nomedi(PIPPO)
La nuova situazione è
- assegnare a MARCO il contenuto di
MARIO
MARCO
<- MARIO
La nuova situazione è
- assegnare a LUIGI il contenuto
della scatola il cui nome è in MARCO
(puntata da MARCO)
LUIGI
<- contenuto(MARCO)
infatti è come se avessimo scritto (il secondo contenuto
è implicito)
LUIGI
<- contenuto(contenuto(MARCO))
La nuova situazione è
- assegnare alla scatola il cui nome è in
MARIO (puntata da
MARIO) il valore 7
contenuto(MARIO)
<- 7
in questo caso occorre scrivere esplicitamente il contenuto,
poichè le variabili a sinistra delle assegnazioni sono
considerate come nome di scatola e non come contenuto.
La nuova situazione è
Nei linguaggi di programmazione occorre ricordare che le scatole=variabili
sono in realtà delle celle della memoria del computer, e che quindi
i nomi di scatola = puntatori sono in realtà degli indirizzi di celle della
memoria, e pertanto hanno delle proprietà particolari.
Per esempio ne esiste solo un numero finito, sono ordinati, esiste il
successivo, il precedente, ...
ESERCIZIO
- Introdurre i puntatori nel linguaggio del calcolatore antropomorfo.
-
Nella metafora scatola=variabile discutere l'introduzione dei puntatori a
puntatori.
I puntatori in un generico linguaggio di programmazione
Un linguaggio di programmazione che supporta il tipo puntatore offre in
genere i seguenti costrutti:
I puntatori in C
- Dichiarazione di variabili di tipo puntatore
-
sintatticamente come le dichiarazioni dei tipi normali ma premettendo un *
davanti al nome delle variabili
int * p, * p2; /*due variabili di tipo puntatore a intero*/
char * c, * c2; /*due variabili di tipo puntatore a carattere*/
-
Operazione che ritorna il puntatore (indirizzo) ad una variabile
- rappresentata da &
int x,y; char a,b;
p = & x; x = 3; /*p contiene l'indirizzo di x (punta a x), x contiene 3*/
c = &b ; a = 'a'; b = 'b';
p = &y;
if(&x == &y) printf("non puo\' essere\n");
else printf("chiaramente sono diversi\n");
p2 = p;
p = &y;
- Operazione che ritorna il contenuto di un puntatore (detta anche
dereferencing, indirezione)
-
*(espressione di tipo puntatore), il suo valore è il
contenuto di espressione di tipo puntatore
a = * c; /* ora a contiene 'b'*/
*p = 4; /*corrisponde ad assegnare 4 a y*/
c = c2; /*errore c2 non e' inizializzato*/
c = p; c = a; /*errori di tipo*/
ESEMPIO
- Programmino che mostra l'uso dei puntatori
-
#include <stdio.h>
main(){
float *x, *y, *z; /* tre variabili di tipo puntatore a float*/
float a, b, c; /* tre variabili di tipo float */
x = &a ; /* x contiene il puntatore (indirizzo) di a */
*x = 1.1; /* a contiene 1.1 */
y = &b ; /* y contiene il puntatore (indirizzo) di b */
b = 1.1; /* b contiene 1.1 */
if(a == b) printf("i contenuti di a e b sono uguali\n");
if(*x == *y) printf("i contenuti dei puntatori contenuti in x e y sono uguali\n");
if(x == y) printf("i puntatori a (indirizzi di) a e a b sono uguali PROBLEMA!\n");
else printf("i puntatori a (indirizzi di) a e a b sono diversi!\n");
c = a + *y;
printf("il valore di c e\' %f e deve essere 2.2\n",c);
y = &c;
c = a + *y;
printf("il valore di c e\' %f e deve essere 3.3\n",c);
}
Il suo output è
i contenuti di a e b sono uguali
i contenuti dei puntatori contenuti in x e y sono uguali
i puntatori a (indirizzi di) a e a b sono diversi!
il valore di c e' 2.200000 e deve essere 2.2
il valore di c e' 3.300000 e deve essere 3.3
ESERCIZI
- Esplicitare le occorrenze implicite dell'operazione contenuto
in alcuni programmi C presentati precedentemente e nel programmino esempio
dato precedentemente.
- Estendere il programmino esempio precedente con ulteriori assegnazioni
e test, prevedendo il risultato. Fare poi il cartone animato della sua
esecuzione evidenziando scatole=variabili e frecce=puntatori.