Discussione esercizio 26:
int controlla(Mazzo M) {
int check[NUMCARTE] = {0};
for (int i = 0 ; i < NUMCARTE ; i++) {
int k = M[i].valore - 1;
if (k < 0 || k > 12) return 0;
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;
}
if (check[k] != 0) return 0;
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;
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,
RE
} Valore;
typedef struct {
Seme seme;
Valore valore;
} Carta;
void stampacarta(Carta c) {
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];
int taglia;
} 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:
- modulo che gestisce la memorizzazione dell'archivio
- modulo che gestisce l'interazione con l'utente
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
):
#ifndef _DIPENDENTE_H
#define _DIPENDENTE_H
typedef struct {
int g, m, a;
} Data;
typedef enum {
IMP,
DIR,
DIRSUP
} Ruolo;
#define MAXL_NOM 20
#define MAXL_COG 40
#define MAXL_SEZ 20
#define MAXL_DIP 30
typedef struct {
char cognome[MAXL_COG + 1];
char nome[MAXL_NOM + 1];
Data nascita;
Ruolo ruolo;
union {
int liv;
char sez[MAXL_SEZ + 1];
char dip[MAXL_DIP + 1];
} info;
} Dipendente;
#endif
L'interfaccia del modulo di memorizzazione:
#ifndef _ARCHIVIO_MEM_H
#define _ARCHIVIO_MEM_H
#include "dipendente.h"
void open_archivio();
void add_dipendente(Dipendente d);
int num_dipendenti();
Dipendente get_dipendente(int i);
void close_archivio();
#endif
//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
.