Indirizzi e puntatori a strutture

Si può determinare sia l'indirizzo della struttura che l'indirizzo di ogni suo elemento. L'operatore che si usa è ancora l'ampersand &. Il seguente programma indstruct.c trova e stampa gli indirizzi di una variabile struttura e dei suoi elementi.

/*
  Indirizzi di una struttura.
*/

#include<stdlib.h>
#include<stdio.h>

/* definisce una struttura */

struct Esempio {
  int a;
  float b;
  char c;
  char *d;
};


int main() {
  struct Esempio x;

  printf("Indirizzo di x: %X\n", &x);
  printf("Indirizzo di x.a: %X\n", &x.a);
  printf("Indirizzo di x.b: %X\n", &x.b);
  printf("Indirizzo di x.c: %X\n", &x.c);
  printf("Indirizzo di x.d: %X\n", &x.d);

  return 0;
}

La figura accanto dà una rappresentazione grafica dello spazio occupato.


Come per i tipi scalari, si possono definire dei puntatori a struttura, in cui possono venire memorizzati indirizzi di strutture. Nell'esempio di sopra, se si definisce una variabile con:

  struct Esempio *p;            /* puntatore a struttura */

Questo definisce p come una variabile il cui contenuto è un indirizzo di memoria. In particolare, è l'indirizzo in cui inizia la zona di memoria in cui è memorizzata una struttura Esempio.

Dal momento che i puntatori a strutture sono variabili che contengono indirizzi di strutture, è lecito fare un assegnamento p=&x, che mette nella variabile p l'indirizzo iniziale di x.

Se p è un puntatore a struttura, allora *p è ovviamente la struttura puntata. In altre parole, se si fa p=&x, allora scrivere x oppure *p è esattamente la stessa cosa. Quindi, per esempio si può passare a una funzione che ha una struttura Esempio come parametro sia x che *p.

Dal momento che *p è una struttura, allora si può anche accedere ai suoi campi. Si faccia però attenzione alle regole di precedenza: si deve scrivere (*p).a per accedere al campo a della struttura, mentre scrivere *p.a produce un errore. Nel caso dell'esempio, (*p).a è equivalente a x.a.

Questa espressione si può abbreviare usando l'operatore freccia: al posto di (*p).a si può scrivere p->a, che migliora di molto la leggibilità. In generale, la espressione puntatore->campo è equivalente a (*puntatore).campo, ossia identifica il campo della struttura puntata. Questa notazione verrà usata molto nell'ambito delle strutture collegate.

Il seguente programma puntstruct.c mostra un uso dei puntatori a strutture.

/*
  Indirizzi di una struttura.
*/

#include<stdlib.h>
#include<stdio.h>

/* definisce una struttura */

struct Esempio {
  int a;
  float b;
  char c;
  char *d;
};


int main() {
  struct Esempio x;
  struct Esempio *p;		/* puntatore a struttura */

  p=&x;				/* prende l'indirizzo della struttura */
				/* da ora in poi, *p e x sono la stessa cosa */

  (*p).a=12;
  printf("Valore di x.a: %d\n", x.a);

  x.c='z';
  printf("Valore di x.c: %c\n", (*p).c);

				/* -> e' equivalente a "(* )." */
  printf("Valore di x.c: %c\n", p->c);

  return 0;
}

La figura qui accanto mostra lo stato della memoria alla fine della esecuzione del programma: la struttura è la stessa del programma precedente, e in più abbiamo una variabile p che contiene l'indirizzo del punto iniziale della zona di memoria in cui si trova la struttura x.