Le strutture /1
Le strutture rappresentano un tipo di variabile che, diversamente dagli array, consente
di gestire in modo compatto, mediante un'unico identificatore, un insieme di valori che
non possiedano necessariamente il medesimo tipo.
Nell'esercizio che segue (e nelle prossime lezioni sulle strutture) svilupperemo un
programma che permetta di implementare le funzionalità necessarie per la gestione del
database di una biblioteca.
Prima di iniziare lo sviluppo del codice, è necessario stabilire quale sia il prototipo di
struttura da utilizzare per rappresentare nel programma la singola unità del database,
ovvero un libro. Gli attributi di tale oggetto che utilizzeremo per sviluppare il prototipo di
struttura sono: il suo titolo, il nome ed il cognome dell'autore ed il numero di pagine.
struct temp {char titolo[200];
char autore[100];
int pagine; } ;
typedef struct temp libro;
In alternativa, per usare una notazione più compatta, si può scrivere:
typedef struct {char titolo[200];
char autore[100];
int pagine; } libro;
Le istruzioni appena scritte permettono di creare un nuovo TIPO di variabile, un tipo
composto da due array di char e da un intero; a tali istruzioni NON CORRISPONDE
ALCUNA ALLOCAZIONE DI MEMORIA. Grazie allo specificatore typedef, a partire da
struct temp, per questioni di comodità e per marcare l'analogia con gli altri tipi
fondamentali del C, è possibile modificare il nome del nuovo tipo di variabile.
Alcune note su typedef
Lo specificatore typedef, oltre che a venir utilizzato per definire un nuovo tipo di dato,
serve anche ad aumentare la portabilità del codice e non è detto debba essere per forza
utilizzato solo su nuovi tipi.
Ad esempio
/* inizio implementazione */
#define NUM 40
typedef int newtype;
void ordina(newtype *vettore)
{newtype temp;
int i=0,scambi=1;
while(scambi)
{scambi=0;
for(i=0;i<NUM;i++)
{if(vettore[i]>vettore[i+1])
{temp=vettore[i];
vettore[i]=vettore[i+1];
vettore[i+1]=temp;
scambi=1;
}
}
}
}
/* fine implementazione */
Sostituendo al tipo int il tipo double, dopo lo specificatore typedef, posso
automaticamente applicare l'ordinamento ad un nuovo tipo di variabile. Usando la
direttiva #ifdef (ovvero la compilazione condizionale), la potenzialità del codice
aumenta ulteriormente.
/* inizio implementazione */
#ifdef INTERO
typedef int newtype;
#endif
#ifdef FLOAT
typedef float newtype;
#endif
#ifdef DOUBLE
typedef double newtype;
#endif
#define NUM 40
void ordina(newtype *vettore)
{newtype temp;
int i=0,scambi=1;
while(scambi)
{scambi=0;
for(i=0;i<NUM;i++)
{if(vettore[i]>vettore[i+1])
{temp=vettore[i];
vettore[i]=vettore[i+1];
vettore[i+1]=temp;
scambi=1;
}
}
}
}
/* fine implementazione */
Prima di iniziare a scrivere il codice, alcune precisazioni; si farà sempre riferimento al
tipo di struttura definito sopra:
typedef struct {char titolo[200];
char autore[100];
int pagine; } libro;
1. Per individuare uno dei caratteri della stringa titolo, ad esempio il quarto
/* dichiaro una variabile di tipo libro */
libro my_var;
char temp;
printf("Inserisci il titolo di un libro");
gets(my_var.titolo); /* titolo è una variabile di tipo char *, contenuta all'interno
della struttura. Per scrivere dei caratteri nella corrispondente area di memoria
devo perciò individuarla, specificando che essa è uno dei membri della struttura
my_var */
temp = my_var.titolo[3]; /* ora temp ha il valore del quarto carattere della
stringa */
temp = *(my_var.titolo +3); /* stessa cosa, usando l'aritmetica dei puntatori */
temp = *(my_var.(titolo +3)); /* GRAVE ERRORE ! */
/* la variabile titolo, da sola, non esiste; essa esiste SOLO come membro della
struttura di tipo libro */
2. Le stesse funzionalità possono essere implementate utilizzando un puntatore a
struttura
/* dichiaro una variabile di tipo libro */
libro my_var;
libro* Punt_libro;
char temp;
printf("Inserisci il titolo di un libro");
gets(Punt_libro->titolo);
temp = Punt_libro->titolo[3];
temp = *(Punt_libro->titolo +3); /* stessa cosa, usando l'aritmetica dei puntatori
*/
temp = *(Punt_libro->(titolo +3)); /* GRAVE ERRORE ! */
/* la variabile titolo, da sola, non esiste; essa esiste SOLO come membro della
struttura di tipo libro */
o anche, usando l'allocazione dinamica
libro* Punt_libro;
Punt_libro = (libro*) malloc(sizeof(libro));
char temp;
printf("Inserisci il titolo di un libro");
gets(Punt_libro->titolo);
temp = Punt_libro->titolo[3];
temp = *(Punt_libro->titolo +3); /* stessa cosa, usando l'aritmetica dei puntatori
*/
temp = *(Punt_libro->(titolo +3)); /* GRAVE ERRORE ! */
/* la variabile titolo, da sola, non esiste; essa esiste SOLO come membro della
struttura di tipo libro */
IMPORTANTE: per determinare la dimensione in byte di una variabile di tipo
struttura utilizzare l'operatore sizeof(). NON è sempre vero che la somma delle
dimensioni in byte delle variabili contenute nella struttura equivalga alla
dimensione in byte della struttura stessa.
3. Alle variabili di tipo struttura NON possono essere applicati tutti gli operatori. Gli
unici operatori utilizzabili sono quello di assegnazione, =, e l'operatore &.
E' perciò possibile fare la COPIA di una struttura, membro a membro, e passare
una struttura ad una funzione per valore.