07. Tipi di Dato Utente
Fondamenti di Programmazione e Laboratorio
Chiara Bodei, Jacopo Soldani
CdL in Matematica, Università di Pisa
a.a. 2020/2021
Variabili di Tipo Strutturato
Tipi Strutturati
struct consente di definire un tipo strutturato, costituito unendo
variabili il cui tipo è uno dei seguenti
• tipi di dato primitivi,• array,• altre struct (ma ci sono delle regole)
Sintassi
struct nome_struct {
tipo1 nome1;
tipo2 nome2;
...
};
Attenzione: La definizione di una struct deve essere sempre
terminata da un ;
1
Esempio di struct
Rappresentazione di un gatto in termini
• della sua età,• del suo peso (in kg) e• dei kg di cibo che assunto nell’ultima settimana
struct gatto {
int eta; //età (anni felini)
double peso; //peso(Kg)
double cibo[7]; //cibo assunto nell’ultima settimana(Kg)
};
2
Dimensione di un Tipo di Dato Strutturato
struct gatto {
int eta; // eta’ (anni felini)
double peso; // peso (Kg)
double cibo[7]; // cibo assunto nell’ultima settimana (Kg)
};
La dimensione di una struct è maggiore o uguale la somma delle
dimensioni dei suoi tipi primitivi.
sizeof(struct gatto) ≥ sizeof(int) + sizeof(double) + 7 ∗ sizeof(double)
Dato che l’uguaglianza non sempre vale, va sempre utilizzata
sizeof(struct ...) (e non la somma delle sizeof)
3
Utilizzo di Tipi Strutturati
Una struct va definita globalmente, all’esterno delle funzioni
Per accedere agli elementi della struct, sia in lettura che in
scrittura, si utilizza la seguente sintassi:
nome struct.nome campo
4
Utilizzo di Tipi Strutturati
Una struct va definita globalmente, all’esterno delle funzioni
Per accedere agli elementi della struct, sia in lettura che in
scrittura, si utilizza la seguente sintassi:
nome struct.nome campo
4
Esempio di Utilizzo struct
struct gatto {
int eta; // eta’ (anni felini)
double peso; // peso (Kg)
double cibo[7]; // cibo assunto nell’ultima settimana(Kg)
};
int main(){
struct gatto felix;
struct gatto luna;
felix.eta = 34;
felix.peso = 6.5:
luna.eta = felix.eta - 5;
luna.cibo[1] = 14.5;
luna.peso = 15.3;
if (luna.peso > 10)
printf("Luna ha mangiato troppe crocchette.\n");
}
5
Inizializzazione di una Variabile di Tipo Strutturato
I valori delle variabili contenute in una struct possono essere
inizializzati anche con una singola istruzione
struct nome struct nome var = { v1, v2, ..., vN }
NB: I valori vengono assegnati alle variabili nello stesso ordine in
cui compaiono nella definizione della struct.
Esempio
struct gatto {
int eta; // eta’ (anni felini)
double peso; // peso (Kg)
double cibo[7]; // cibo assunto nell’ultima settimana (Kg)
};
int main(void){
struct gatto felix = {14, 5.7, {0.2, 0.1, 0.3, 0.3, 0.2, 0.5, 0.3}};
...
} 6
Array e struct
Array in struct
I campi di tipo array si
accedono esattamente come
tutti gli altri
struct gatto {
int eta;
double peso;
double cibo[7];
};
int main(void){
struct gatto felix;
felix.cibo[2] = 6.45;
...
}
Array di struct
Gli array di struct
funzionano esattamente come
gli array di tipi primitivi
struct gatto {
int eta;
double peso;
double cibo[7];
};
int main(){
struct gatto gatti[10];
gatti[2].eta = 15;
gatti[2].cibo[3] = 4.32;
...
}
7
Array e struct
Array in struct
I campi di tipo array si
accedono esattamente come
tutti gli altri
struct gatto {
int eta;
double peso;
double cibo[7];
};
int main(void){
struct gatto felix;
felix.cibo[2] = 6.45;
...
}
Array di struct
Gli array di struct
funzionano esattamente come
gli array di tipi primitivi
struct gatto {
int eta;
double peso;
double cibo[7];
};
int main(){
struct gatto gatti[10];
gatti[2].eta = 15;
gatti[2].cibo[3] = 4.32;
...
}
7
Funzioni e Variabili di Tipo
Strutturato
Passaggio di una struct per parametro
Il passaggio di una variabile di tipo strutturato funziona allo stesso
modo del passaggio delle variabili. Es. struct gatto felix
• passaggio per valore: controllaPeso(felix) crea una copiadella variabile felix e la assegna al parametro formale di
controllaPeso
• passaggio per riferimento: aggiornaPeso(&felix,6.57)assegna l’indirizzo della variabile felix nel parametro formale
di aggiornaPeso (in modo che le modifiche fatte dalla
funzione siano visibili anche dopo che la funzione è terminata)
Attenzione: L’accesso ai campi di una struct tramite puntatore è
però diverso
8
Passaggio di una struct per parametro
Il passaggio di una variabile di tipo strutturato funziona allo stesso
modo del passaggio delle variabili. Es. struct gatto felix
• passaggio per valore: controllaPeso(felix) crea una copiadella variabile felix e la assegna al parametro formale di
controllaPeso
• passaggio per riferimento: aggiornaPeso(&felix,6.57)assegna l’indirizzo della variabile felix nel parametro formale
di aggiornaPeso (in modo che le modifiche fatte dalla
funzione siano visibili anche dopo che la funzione è terminata)
Attenzione: L’accesso ai campi di una struct tramite puntatore è
però diverso
8
Puntatori e Variabili di Tipo Strutturato
Se x è un puntatore ad una variabile di tipo strutturato, un campo
della variabile puntata si accede mediante x->campo
Esempio
struct gatto {
int eta;
double peso;
double cibo[7];
};
void aggiornaPeso(struct gatto* g, double nuovoPeso){
g->peso = nuovoPeso; // accesso a campo di struct puntata
}
int main(){
struct gatto felix = {14, 5.7, {0.2, 0.1, 0.3, 0.3, 0.2, 0.5, 0.3}};
aggiorna_peso(&felix, 6.2); // passaggio struct per riferimento
return 0;
}
9
Accesso a Variabili di Tipo Strutturato: Riepilogo
x.campo per accedere ad un campo di una variabile x di tipo
strutturato
Esempio
void stampaEta(struct gatto g) {
printf("%d", g.eta);
}
p->campo (oppure (*p).campo) per accedere ad un campo di una
variabile di tipo strutturato puntata dal puntatore p
Esempio
void aggiornaPeso(struct gatto* g, double nuovoPeso){
g->peso = nuovoPeso; // oppure (*g).peso = nuovoPeso;
}
10
Accesso a Variabili di Tipo Strutturato: Riepilogo
x.campo per accedere ad un campo di una variabile x di tipo
strutturato
Esempio
void stampaEta(struct gatto g) {
printf("%d", g.eta);
}
p->campo (oppure (*p).campo) per accedere ad un campo di una
variabile di tipo strutturato puntata dal puntatore p
Esempio
void aggiornaPeso(struct gatto* g, double nuovoPeso){
g->peso = nuovoPeso; // oppure (*g).peso = nuovoPeso;
}
10
Annidare Tipi di Dato Strutturati
Annidare struct
Una struct può contenere un’altra struct, ma ci sono delle
regole da rispettare
• La dimensione della struct annidata deve essere finita,costante e determinabile a tempo di compilazione
• Una struct s2 può contenere una struct sq solo se s1 èdefinita prima nel programma
• L’annidamento delle struct deve formare un albero
(NB: Le regole sopra impediscono di definire struct ricorsive)
11
Annidare struct: Esempio
Definizione del tipo struct nazione, al cui interno è annidato iltipo struct citta per rappresentarne la capitale
struct citta {
int n_cittadini;
double latitudine;
double longitudine;
};
struct nazione {
struct citta capitale; // "struct citta" definita sopra
double superficie;
int fuso_orario;
};
(NB: struct citta NON può avere campi di tipo struct
nazione, altrimenti non sarebbe possibile determinare lo spazio
occupato da entrambe le struct (e anche perché struct
nazione è definito dopo).
12
Annidare struct: Esempio
Definizione del tipo struct nazione, al cui interno è annidato iltipo struct citta per rappresentarne la capitale
struct citta {
int n_cittadini;
double latitudine;
double longitudine;
};
struct nazione {
struct citta capitale; // "struct citta" definita sopra
double superficie;
int fuso_orario;
};
(NB: struct citta NON può avere campi di tipo struct
nazione, altrimenti non sarebbe possibile determinare lo spazio
occupato da entrambe le struct (e anche perché struct
nazione è definito dopo).
12
Collegare struct
Ci sono dei casi in cui le struct devono logicamente chiamarsi tra
di loro (annidamento ricorsivo).
Esempio: Albero Genealogico (sbagliato)
struct persona {
struct persona madre;
struct persona padre;
int anno_nascita;
};
Avrebbe dimensione “infinita”. Come risolviamo?
13
Collegare struct (2)
I puntatori a struct hanno sempre la stessa dimensione (visto che
rappresentano indirizzi di memore. Soluzione:
Esempio: Albero Genealogico (corretto)
struct persona {
struct persona* madre;
struct persona* padre;
int anno_nascita;
};
14
Accesso alle Strutture Puntate
struct persona {
struct persona* madre;
struct persona* padre;
int anno_nascita;
};
int main(){
struct persona giovanni, alice ;
struct persona cecilia;
giovanni.anno_nascita = 1980;
cecilia.anno_nascita = 2005;
cecilia.madre = &alice;
cecilia.padre = &giovanni;
(cecilia.madre)->anno_nascita = 1982;
// o, in alternativa: ((*cecilia.madre)).anno_nascita = 1982;
printf("cecilia-madre-anno: %d\n", cecilia.madre->anno_nascita); // 1982
printf("cecilia-padre-anno: %d\n", cecilia.padre->anno_nascita); // 1980
printf("cecilia: %d\n", cecilia.anno_nascita); // 2005
}15
Aliasing
Assegnare Alias a Tipi
typedef consente di assegnare alias ai tipi, ovvero nomi alternativi
per tipi di dato già esistenti
typedef nomeTipo aliasTipo
Esempio
Definire un alias eta t per il tipo intero, per rappresentare l’età di
una persona.
typedef int eta_t;
int main(void) {
eta_t eta_mario = 67; // equivalente a int eta_mario = 67;
...
}
16
typedef e struct
I typedef sono particolarmente utili per creare alias per tipi di
dato strutturati (struct) o enumerat (enum, che vedremo dopo)
Esempio
struct studente_struct{
int matricola;
int anno_nascita;
};
typedef struct studente_struct studente;
int main(){
studente giorgio; // invece di "struct studente_struct giorgio"
giorgio.matricola = 666;
...
}
17
typedef e struct (2)
È anche possibile definire tipo di dato strutturato (struct)
anonimo, assegnandogli direttamente un alias con typedef (e
tipicamente si fa cos̀ı)
Esempio
typedef struct {
int matricola;
int anno_nascita;
} studente;
int main(){
studente giorgio;
giorgio.matricola = 666;
...
}
18
Tipi di Dato Enumerati
enum
enum consente di definire tipi di dato il cui range di valori è
limitato ai valori enumerati
Esempio
enum colore_gatto {
rosso,
nero,
tigrato
};
int main(void) {
enum colore_gatto colore;
colore = rosso;
}
19
enum e typedef
Come con le struct, è possibile definire un enum e il suo typedef
in un solo comando (e tipicamente si fa cos̀ı)
Esempio
typedef enum {
rosso,
nero,
tigrato
} colore_gatto;
int main(void) {
colore_gatto colore;
colore = rosso;
}
20
enum, struct e typedef
typedef enum { // definizione del tipo enumerato "colore_gatto"
rosso,
nero,
tigrato
} colore_gatto;
typedef struct { // definizione del tipo strutturato "gatto"
colore_gatto colore; // utilizzo del tipo enumerato definito sopra
int eta;
double peso;
} gatto;
int main(void){
gatto felix; // utilizzo del tipo strutturato definito sopra
felix.colore = rosso;
if (felix.colore != nero)
printf("Volevo un gatto nero!");
return 0;
}
21
Esercizi
Esercizi sulla Piattaforma di Autovalutazione
Esercizi della Lezione 7 sulla piattaforma
1. Gestore del gattile
2. Gestione dipendenti
3. Famiglia
22
Variabili di Tipo StrutturatoFunzioni e Variabili di Tipo StrutturatoAnnidare Tipi di Dato StrutturatiAliasingTipi di Dato EnumeratiEsercizi