IL TIPO DI DATO 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.
Riassumendo il tipo di dato puntatori è come segue:
- valori
- i nomi delle variabili (più precisamente saranno gli indirizzi
delle corrispondenti celle di memoria)
- costanti
- in genere esiste una sola costante che corrisponde al puntatore nullo,
cioè non è il nome di alcuna variabile, indicata da null o
nil
- operazioni
- confronto per uguaglianza, per differenza
a volte ricordando che i corrispondenti indirizzi di memoria hanno una struttura
di ordine discreto, abbiamo operazioni che ritornano il prossimo, il
precedente
Usare i puntatori in un generico linguaggio di
programmazione
Consideriamo la seguente rappresentazione grafica di una situazione di un
programma che usa i puntatori:
La scatola (variabile) MARIO contiene il nome di
un'altra scatola
(PIPPO) e
quindi si dice che punta a PIPPO,
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).
Vediamo ora alcune tipiche operazioni con le variabili (scatole) di tipo
puntatore.
- Assegnare a MARIO il nome di
LUIGI
-
MARIO <-LUIGI
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(LUIGI)
e quindi si avrebbe anche un errore di tipo (tentativo di mettere 0
in una scatola che contiene dei puntatori [nomi di variabili]).
Esiste invece un'altra operazione che indica esplicitamente di
considerare un nome di scatola come nome e non come contenuto.
MARIO
<- nomedi(LUIGI)
La nuova situazione sarà
- Assegnare a MARCO il contenuto di
MARIO
-
MARCO
<- MARIO
La nuova situazione
- Assegnare a PIPPO il contenuto
della scatola il cui nome è in MARCO
(puntata da MARCO)
-
PIPPO
<- contenuto(MARCO)
infatti è come se avessimo scritto (il secondo contenuto
è implicito)
PIPPO
<- contenuto(contenuto(MARCO))
La nuova situazione sarà
- 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, ...
I puntatori in un generico linguaggio di programmazione
Un linguaggio di programmazione che supporta il tipo puntatore offre in
genere i seguenti costrutti:
ESERCIZIO
- Introdurre i puntatori nel linguaggio del calcolatore antropomorfo.
-
Nella metafora scatola=variabile discutere l'introduzione dei puntatori a
puntatori.
- Estendere la metafora delle scatole a considerare l'allocazione e
deallocazione dinamica delle celle di memoria.
I puntatori in C
- Dichiarazione di variabili di tipo puntatore
-
Sono sintatticamente simili alle dichiarazioni dei tipi normali, ma
occorre premettere un * davanti al nome delle variabili
-
Operazione che ritorna il puntatore ad (indirizzo di) una variabile
- è rappresentata da & prefisso
- Operazione che ritorna il contenuto di un puntatore (detta anche
dereferencing, indirezione)
-
*(espressione di tipo puntatore), il suo valore è il
contenuto della cella di memoria (variabile) [scatola] individuata dal
valore di espressione di tipo puntatore
Vediamo alcuni esempietti di tali costrutti:
main()
{ int * p, * p2; /*due variabili di tipo puntatore a intero*/
char * c, * c2; /*due variabili di tipo puntatore a carattere*/
int x, y;
char a,b;
p = & x; x = 3;
/*p contiene l'indirizzo di x (punta a x) [il nome di 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;
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 inutile 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 sopra.
-
Fare il cartone animato dell'esecuzione del programmino dato sopra,
seguendo los tile utilizzato all'inizio di questa pagina.
- Estendere il programmino esempio precedente con ulteriori assegnazioni
e test, prevedendo il risultato.
Fare poi il cartone animato della sua
esecuzione.