Arimetica dei puntatori

  1. cosa succede quando si somma un intero a un puntatore
  2. perchè non si fa la somma numerica
  3. la regola generale: un puntatore è l'indirizzo di memoria in cui sono memorizzate una o più variabili di un certo tipo
  4. p+i dice l'indirizzo della i+1-esima variabile
  5. *(p+i) e p[i] sono la stessa cosa

Ci sono due modi di interpretare un puntatore: una variabile int *p è l'indirizzo iniziale della zona di memoria in cui si trova un intero, oppure è un vettore dinamico. Abbiamo poi visto che i vettori dinamici sono semplicemente dei puntatori a un indirizzo di una cella di memoria da cui inizia una sequenza di dati (nel nostro esempio, di interi).

Possiamo quindi dire che, in entrambi i casi, un puntatore a intero è l'indirizzo iniziale di una zona di memoria in cui sono memorizzati uno o più interi consecutivamente. La notazione p[i], quando p è un puntatore, serve a indicare l'i-esimo intero di questa sequenza.

In C, è possibile effettuare delle semplici operazioni arimetiche sui puntatori, e fra puntatori e interi. Il caso più semplice è quello in cui si somma un intero a un puntatore. Il risultato non è però quello che ci si potrebbe aspettare a prima vista. Infatti, p+3 non coincide con il valore di p a cui si somma tre. Il programma nosomma.c mostra questo fatto.

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

  p=&a;

  printf("p vale %x\np+3 vale %x\n", p, p+3);

  return 0;
}

Il risultato di questo programma potrebbe essere:

p vale bffff418
p+3 vale bffff424

La cosa essenziale è che la stampa di p+3 non produce la stampa del valore numerico di p a cui è stato sommato 3.

Quando si somma un intero a un puntatore non viene fatta la somma numerica perchè l'indirizzo che si otterrebbe in questo modo sarebbe poco significativo. Infatti, sarebbe l'indirizzo del terzo byte del primo intero della zona puntata da p. L'indirizzo di un byte che si trova in mezzo alla zona di memoria di una variabile non è molto utile. Per questa ragione, il risultato della somma p+3 viene definito come l'indirizzo del terzo intero della sequenza puntata da p. Il suo valore numerico è quindi ottenuto sommando a p il numero di byte occupati dall'intero, moltiplicato per tre.

Tutto questo discorso vale per gli interi. Per puntatori a un tipo di dato generico la regola è:

un puntatore a un tipo è l'indirizzo iniziale di una zona di memoria in cui sono memorizzate una o più variabili di quel tipo.

p+i è l'indirizzo iniziale dell'i+1-esimo elemento della sequenza puntata da p

Se per esempio il tipo double si rappresenta con otto byte, e p è definito come double *p, allora p è un puntatore a double, ossia è l'indirizzo iniziale di una zona di memoria in cui si trova una sequenza di uno o più reali. Per la somma, p+3 è l'indirizzo del terzo elemento della sequenza: dato che ogni reale occupa otto byte, il valore numerico di p+3 è il valore numerico di p più 3*8.

La figura qui sotto indica gli indirizzi i cui valori sono rappresentati da somme fra puntatori e interi, nel caso di un puntatore a intero.

Dal momento che b è l'indirizzo iniziale di un intero, possiamo accedere a questo intero usando la notazione *b. Ma anche b+1 è l'indirizzo iniziale di un intero, a cui possiamo quindi accedere come *(b+1). Lo stesso vale per *(b+2), *(b+3), ecc. Facendo un confronto con la figura qui sopra, si vede chiaramente come *b e b[0] sono la stessa cosa. Inoltre, *(b+1) e b[1] sono ancora la stessa identica zona di memoria, ecc. Questo avviene per tipi qualsiasi, non solo interi, ed è dovuta al fatto che sia la notazione b[i] che la espressione *(b+i) indicano l'i-esimo elemento della zona di memoria puntata da b. Questa è una regola generale: b[i] e *(b+i) sono equivalenti.

È anche possibile sottrare un intero a una variabile di tipo puntatore, ma per il momento questo non ci interessa (in altre parole, si può fare p-3, che ha un significato abbastanza chiaro). È anche possibile fare la sottrazione fra due puntatori.

Il concetto generale che raccoglie tutte queste diverse espressioni è quello di lvalue, che è una qualsiasi espressione che ritorna un indirizzo.