Lezione 15
Discussione esercizio 26:
/* Controlla se il mazzo M contiene tutte le carte */
int controlla(Mazzo M) {    
    //ad ogni carta è assegnato un indice univoco k da 0 a 51: k = (v - 1) + 13*s 
    //dove v è il valore e s = 0 per 'c', 1 per 'q', 2 per 'f' e 3 per 'p'.
    int check[NUMCARTE] = {0};   //check delle carte: per ogni carta incontrata di
                                 //indice k il corrispondente elemento è posto a 1 
    for (int i = 0 ; i < NUMCARTE ; i++) {
        int k = M[i].valore - 1;
        if (k < 0 || k > 12) return 0;    //valore non valido
        switch (M[i].seme) {
            case 'c': break;
            case 'q': k += 13; break;
            case 'f': k += 26; break;
            case 'p': k += 39; break;
            default: return 0;            //seme non valido
        }
        if (check[k] != 0) return 0;      //carta già incontrata
        check[k] = 1;
    }
    return 1;
}
Discussione esercizio 27:
#include <string.h>

typedef struct {
    long    matricola;
    char    nome[20];
    char    cognome[30];
    int     num_esami;
} Studente;

/* Ritorna l'indice, nell'array stu di dimensione n, dello studente con 
 * cognome c, se non è presente ritorna -1. */
int cerca(Studente stu[], int n, char *c) {
    for (int i = 0 ; i < n ; i++)
        if (strcmp(stu[i].cognome, c) == 0)
            return i;
    return -1;
}
Enumerazioni  enum : gruppo di costanti intere.
enum Nome {
    COST1,     //se non vengono assegnanti dei valori questi sono
    COST2,     //assegnati a partire da 0
    COST3,
    .
    .
    .
    COSTK
};
Esempio: definizione alternativa di una struct Carta che usa enumerazioni per i tipi dei membri e una funzione che stampa una Carta:
#include <stdio.h>

typedef enum {
    CUORI,
    QUADRI,
    FIORI,
    PICCHE
} Seme;

typedef enum {
    ASSO = 1,
    FANTE = 11,
    REGINA,    //ha valore 12
    RE         //ha valore 13
} Valore;

typedef struct {
    Seme    seme;
    Valore  valore;
} Carta;

void stampacarta(Carta c) {     //stampa una carta
    switch (c.valore) {
        case ASSO: printf("Asso"); break;
        case FANTE: printf("Fante"); break;
        case REGINA: printf("Regina"); break;
        case RE: printf("Re"); break;
        default: printf("%d", c.valore);
    }
    printf(" di ");
    switch (c.seme) {
        case CUORI: printf("cuori"); break;
        case QUADRI: printf("quadri"); break;
        case FIORI: printf("fiori"); break;
        case PICCHE: printf("picche"); break;
    }
    printf("\n");
}


int main() {
    Carta c1 = {CUORI, 10}, c2 = {PICCHE, FANTE};
    Carta c3 = {FIORI, RE}, c4 = {CUORI, ASSO};
    stampacarta(c1);
    stampacarta(c2);
    stampacarta(c3);
    stampacarta(c4);
}
Non c'è alcun controllo sui tipi enum, sono trattati come equivalenti a int.
Le unioni  union . La sintassi è identica a quella delle struct ma i campi di una union sono l'uno in alternativa agli altri, cioè, in ogni momento uno solo dei campi di una union è valido. Esempi:
typedef union {
    int     intero;
    double  decimale;
} Numero;

int main() {
    Numero num;
    num.intero = 12;    //adesso il campo intero è valido ma il campo 
                        //decimale non è valido
    num.decimale = 0.5; //adesso il campo decimale è valido ma il campo
                        //intero non è valido
    Numero n = {12};               //inizializzazione del primo campo (intero)
    Numero n2 = {.decimale = 0.5}; //inizializzazione del campo decimale
}
Il sizeof di una union è maggiore o uguale al massimo dei sizeof dei suoi campi, e spesso è proprio uguale a questo massimo.
Esempio:
typedef enum {
    TELEVISORE,
    LAVATRICE,
    MAGLIONE
} TipoArt;

typedef struct {
    TipoArt    tipo;
    char       marca[30];
    float      prezzo;
    union {
        char modello[20];     //solo per TELEVISORE e LAVATRICE
        int  taglia;          //solo per MAGLIONE
    }          info;
} Articolo;
Discussione di un programma che gestisce (in memoria primaria) un piccolo archivio relativo ai dipendenti di una ipotetica azienda. Il programma deve permettere di effettuare almeno le seguenti operazioni: inserimento dei dati di un nuovo dipendente, stampa dei dati relativi a tutti i dipendenti e ricerca di un dipendente in base al cognome. Struttura del programma e decomposizione del programma in due moduli: Vi è anche un modulo che contiene alcune funzioni di utilità. Discussione dei vantaggi offerti da una tale decomposizione in moduli. Cenni sulla separazione interfaccia-implementazione. Decomposizione in files del programma:
 ______ util.h _______      ___ dipendente.h _____
|                     |    |                      |
| Prototipi delle     |    | Definizioni dei dati |
| funzioni di utilità |__  | dell'archivio        |     _ archivio_mem.h _
|_____________________|  | |______________________|    |                  |
          |              |            |              __| Prototipi delle  |
 ______ util.c _______   |  __ archivio_main.c ___  |  | funzioni che si  |
|                     |  | |                      | |  | occupano della   |
| Implementazione     |  |_| Il main e la gestione|_|  | memorizzazione   |
| delle funzioni di   |    | dell'interazione con |    |__________________|
| utilità             |    | l'utente             |             |
|_____________________|    |______________________|     _ archivio_mem.c _
                                                       |                  |
                                                       | Implementazione  |
                                                       | delle funzioni   |
                                                       | che si occupano  |
                                                       | della memoriz.   |
                                                       |__________________|
Uso delle direttive #ifndef - #endif per evitare che il contenuto di un file header (file .h) possa essere incluso più di una volta nello stesso file. Definizione della struct che rappresenta i dati relativi ad un dipendente (nel file dipendente.h):
/**************************** FILE dipendente.h *******************************/
#ifndef _DIPENDENTE_H
#define _DIPENDENTE_H

typedef struct {    //rappresenta una data
    int g, m, a;
} Data;

typedef enum {
    IMP,      //impiegato
    DIR,      //dirigente
    DIRSUP    //dirigente superiore
} Ruolo; //ogni dipendente appartiene ad uno dei ruoli sopra specificati

#define MAXL_NOM    20      //massima lunghezza del nome
#define MAXL_COG    40      //massima lunghezza del cognome
#define MAXL_SEZ    20      //massima lunghezza del nome di una sezione
#define MAXL_DIP    30      //massima lunghezza del nome di un dipartimento

typedef struct {
    char         cognome[MAXL_COG + 1]; //stringa
    char         nome[MAXL_NOM + 1];    //stringa
    Data         nascita;
    Ruolo        ruolo;
    union {
        int liv;                 //livello, solo per impiegati
        char sez[MAXL_SEZ + 1];  //solo per dirigenti (nome della sezione diretta)
        char dip[MAXL_DIP + 1];  //solo per dirigenti superiori (nome del
    }           info;                                      //dipartimento diretto)
} Dipendente;

#endif  /* _DIPENDENTE_H */
L'interfaccia del modulo di memorizzazione:
/**************************** FILE archivio_mem.h *****************************/
#ifndef _ARCHIVIO_MEM_H
#define _ARCHIVIO_MEM_H

#include "dipendente.h"

/* L'interfaccia per la gestione della memorizzazione dell'archivio permette di 
 * disaccoppiare l'uso di queste funzioni dalla loro particolare implementazione.
 * Così il modulo che usa questa interfaccia non deve preoccuparsi dei dettagli 
 * della particolare implementazione, ad esempio, se usa la memoria primaria o 
 * la memoria secondaria, se usa array, liste, alberi o tabelle hash, ecc. */

void open_archivio();               //predispone l'archivio per essere usato
void add_dipendente(Dipendente d);  //aggiunge un dipendente all'archvio
int num_dipendenti();               //ritorna il numero di dipendenti in archivio
Dipendente get_dipendente(int i);   //ritorna l'i-esimo dipendente in archivio
void close_archivio();              //chiude l'archivio (libera eventuali risorse)

#endif  /* _ARCHIVIO_MEM_H */
//TO BE CONTINUED...
Esercizio 28    Scrivere una funzione Dipendente input_dipendente() che permette all'utente di inserire i valori dei campi di una struct Dipendente e che ritorna la struct così riempita.
Esercizio 29    Scrivere una funzione void stampadip(Dipendente d) che stampa i dati della struct d.