07. Tipi di Dato Utentepages.di.unipi.it/bodei/CORSO_FP_20/FP/Lezioni/Tipi... · 2020. 11. 18. ·...

34
07. Tipi di Dato Utente Fondamenti di Programmazione e Laboratorio Chiara Bodei, Jacopo Soldani CdL in Matematica, Universit` a di Pisa a.a. 2020/2021

Transcript of 07. Tipi di Dato Utentepages.di.unipi.it/bodei/CORSO_FP_20/FP/Lezioni/Tipi... · 2020. 11. 18. ·...

  • 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