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