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. |