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

  1. Introdurre i puntatori nel linguaggio del calcolatore antropomorfo.
  2. Nella metafora scatola=variabile discutere l'introduzione dei puntatori a puntatori.
  3. 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

  1. Esplicitare le occorrenze implicite dell'operazione contenuto in alcuni programmi C presentati precedentemente e nel programmino esempio dato sopra.
  2. Fare il cartone animato dell'esecuzione del programmino dato sopra, seguendo los tile utilizzato all'inizio di questa pagina.
  3. Estendere il programmino esempio precedente con ulteriori assegnazioni e test, prevedendo il risultato.
    Fare poi il cartone animato della sua esecuzione.