Valore e indirizzo

  1. tutte le variabili hanno valore e indirizzo
  2. questo vale anche per i puntatori
  3. per i puntatori, sono entrambi indirizzi di memoria
  4. sono comunque due cose diverse

Tutte le variabili hanno un valore e un indirizzo. Questa regola vale anche per le variabili puntatore: anche loro hanno un indirizzo (la zona di memoria in sui si trovano) e un valore (quello che è memorizzato). Quello che le rende diverse è il fatto che il valore in esso memorizzato è a sua volta un indirizzo.

In altre parole, le variabili puntatore sono sempre zone di memoria in cui viene memorizzato un numero. Mentre le variabili intere e reali contengono valori interi e reali, il valore memorizzato in una variabile puntatore è un numero che indica una posizione di memoria.

Anche se il valore di una variabile puntatore e il suo indirizzo sono entrambe posizioni di memoria, sono comunque due cose diverse: l'indirizzo è la posizione iniziale della memoria occupata, mentre il valore è quello che si trova memorizzato, che a sua volta un indirizzo di memoria (in generale, uno diverso). Il seguente programma valind.c illustra la differenza.

/*
  Valore e indirizzo sono diversi.
*/

int main() {
  int a=60;
  int *p;

  p=&a;		

  printf("&a=%x a=%x\n", &a, a);
  printf("&p=%x p=%x\n", &p, p);

  return 0;
}

Questo programma stampa indirizzo e valore per le due variabili a e p. Tutte le variabili hanno un indirizzo (la posizione in memoria) e un valore (quello che c'è memorizzato). Questo vale quindi sia per a, che è una variabile intera, che per p, che è un puntatore.

Quando si esegue il programma, viene creata una zona di memoria per ognuna delle variabili. In questo caso, viene creata una zona per a ed una zona per p.

Nella figura a sinistra si vede un possibile stato della memoria dopo che le variabili sono state create. Quando si assegna ad a il valore 60, questo valore viene scritto nella sua posizione di memoria.

Quando si esegue l'istruzione p=&a, l'indirizzo di a viene scritto in p. Quando si fanno queste figure di esempio, è bene scrivere dei valori di esempio per le posizioni di memoria. In questa figura, per esempio, la posizione iniziale di a è eff0b. Si tratta ovviamente di un valore di esempio: la posizione effettiva della variabile viene determinata soltanto quando si esegue il programma. In ogni caso, il numero che dice la posizione iniziale di a viene memorizzato in p.

Quello che verrebbe stampato, in questo caso, è:

&a=eff0b a=3c
&p=eff12 p=eff0b

Il primo valore delle due righe è l'indirizzo delle due variabili. I due indirizzi sono necessariamente diversi, dal momento che ogni variabile occupa una sua zona di memoria diversa da quelle delle altre.

Il secondo numero stampato è il valore delle due variabili. Il valore memorizzato in a, nel nostro caso, è 60, che viene stampato in esadecimale. Nella seconda riga, il secondo numero stampato è il valore memorizzato nella variabile p. Dato che in p abbiamo messo l'indirizzo di a (quando abbiamo eseguito l'istruzione p=&a) viene stampato appunto l'indirizzo di a.

La variabile p, come tutte le variabili, ha sia un indirizzo che un valore. Soltanto che, a differenza di a, il valore di p è a sua volta un indirizzo (in questo caso, quello di a). Il fatto che il valore di una variabile puntatore sia un indirizzo può a volte causare confusione. Basta però disegnare lo stato della memoria per chiarire la situazione.

Facciamo ora una precisazione sulla rappresentazione grafica della memoria. Nella figura di sopra abbiamo messo dei valori numerici di esempio per rappresentare gli indirizzi delle variabili (eff0b per l'indirizzo di a e eff12 per l'indirizzo di p). Va tenuto sempre presente che questi sono solo indirizzi di esempio: se si esegue il programma una seconda volta, potrebbero venire stampati degli indirizzi diversi, per esempio ffb02 ed ffb12. Nel seguito, si mettono comunque dei valori specifici per gli indirizzi, ma va tenuto presente che si tratta solo di valori di esempio.

La figura qui accanto mostra una rappresentazione grafica diversa, che non ha questo problema. Per indicare che un puntatore contiene un certo indirizzo, mettiamo una freccia che termina con la locazione a quell'indirizzo. Per esempio, l'istruzione p=& mette in p l'indirizzo di a. Questo si può rappresentare come una freccia che parte dalle locazioni occupate da p e punta alla prima locazione occupata da a. Questa rappresentazione grafica permette di far capire quale è l'indirizzo memorizzato in una variabile puntatore senza dover scrivere valori numerici di esempio per gli indirizzi.

Questa rappresentazione risulta particolarmente comoda per visualizzare lo stato della memoria quando si eseguono programmi che contengono molti puntatori.