Discussione esercizio 28:
Per implementare la funzione
input_dipendente()
si possono usare delle
funzioni (ad es. per leggere una linea dallo standard input) che sono di
applicabilità più generale e che conviene raggruppare nel modulo
delle funzioni di utilità. Ecco quindi l'interfaccia delle funzioni di
utilità:
#ifndef _UTIL_H
#define _UTIL_H
int input_line(char *prompt, char line[], int maxlen);
int input_int();
char input_char();
#endif
L'implementazione (nel file
util.c
) è lasciata come esercizio. Adesso possiamo
implementare la funzione
input_dipendente()
:
#include <stdio.h>
#include "dipendente.h"
#include "util.h"
Dipendente input_dipendente() {
Dipendente nuovo;
input_line("Nome: ", nuovo.nome, MAXL_NOM);
input_line("Cognome: ", nuovo.cognome, MAXL_COG);
printf("Nascita (g/m/a): ");
Data *dn = &(nuovo.nascita);
scanf("%d/%d/%d", &(dn->g), &(dn->m), &(dn->a));
printf("Ruolo (%d = IMP, %d = DIR, %d = DIRSUP): ", IMP, DIR, DIRSUP);
switch (input_int()) {
case IMP: nuovo.ruolo = IMP; break;
case DIR: nuovo.ruolo = DIR; break;
case DIRSUP: nuovo.ruolo = DIRSUP; break;
default: nuovo.ruolo = IMP;
}
switch (nuovo.ruolo) {
case IMP:
printf("Livello: ");
nuovo.info.liv = input_int();
break;
case DIR:
input_line("Sezione: ", nuovo.info.sez, MAXL_SEZ);
break;
case DIRSUP:
input_line("Dipartimento: ", nuovo.info.dip, MAXL_DIP);
break;
}
return nuovo;
}
Discussione esercizio 29:
#include <stdio.h>
#include "dipendente.h"
void stampadip(Dipendente d) {
printf("Nome: %s Cognome: %s\n", d.nome, d.cognome);
printf("Data di nascita: %d/%d/%d\n", d.nascita.g, d.nascita.m, d.nascita.a);
switch (d.ruolo) {
case IMP:
printf("Impiegato - livello: %d\n", d.info.liv);
break;
case DIR:
printf("Dirigente - sezione: %s\n", d.info.sez);
break;
case DIRSUP:
printf("Dirigente sup. - dipartimento: %s\n", d.info.dip);
break;
}
}
Passiamo ora all'implementazione del modulo che gestisce l'interazione con l'utente, usando anche le funzioni appena definite:
#include "util.h"
#include <stdio.h>
#include <ctype.h>
void inizio();
void aggiungi();
void stampa();
void ricerca();
void fine();
int main() {
inizio();
int quit = 0;
do {
printf("A) Aggiungi\n");
printf("S) Stampa\n");
printf("R) Ricerca\n");
printf("F) Fine\n");
switch (toupper(input_char())) {
case 'A': aggiungi(); break;
case 'S': stampa(); break;
case 'R': ricerca(); break;
case 'F': quit = 1; break;
default: printf("Scelta non valida\n");
}
} while (!quit);
fine();
}
#include "archivio_mem.h"
#include <stdlib.h>
#include <string.h>
Dipendente input_dipendente() {...}
void stampadip(Dipendente d) {...}
void inizio() {
printf("ARCHIVIO DIPENDENTI\n\n");
open_archivio();
}
void aggiungi() {
add_dipendente(input_dipendente());
}
void stampa() {
int i, nd = num_dipendenti();
printf("Numero dipendenti: %d\n", nd);
for (i = 0 ; i < nd ; i++) {
printf("------------------------------------\n");
stampadip(get_dipendente(i));
}
printf("------------------------------------\n");
}
void ricerca() {
char cognome[MAXL_COG+1];
input_line("Cognome da ricercare: ", cognome, MAXL_COG);
int i = 0, nd = num_dipendenti();
while (i < nd) {
Dipendente d = get_dipendente(i);
if (strcmp(cognome, d.cognome) == 0) {
stampadip(d);
return;
}
i++;
}
printf("Non trovato\n");
}
void fine() {
close_archivio();
printf("ARCHIVIO CHIUSO\n");
}
Implementazione del modulo di memorizzazione (file
archivio_mem.c
) tramite array
allocato dinamicamente.
#include "archivio_mem.h"
#include <stdlib.h>
static Dipendente *archivio = NULL;
static int numDipendenti = 0;
void open_archivio() {}
void add_dipendente(Dipendente d) {
archivio = realloc(archivio, (numDipendenti + 1)*sizeof(Dipendente));
archivio[numDipendenti++] = d;
}
int num_dipendenti() {
return numDipendenti;
}
Dipendente get_dipendente(int i) {
return archivio[i];
}
void close_archivio() {
if (archivio != NULL) {
free(archivio);
archivio = NULL;
numDipendenti = 0;
}
}
Discussione circa l'uso di
Variabili globali . Il qualificatore
static
per mantenere locale la definizione di una variabile o di una funzione.
Le
liste : struttura dati dinamica, utile per gestire insiemi (o sequenze)
soggetti a molti inserimenti ed eliminazioni di elementi. In alcuni casi permette uno
sfruttamento più efficace della memoria rispetto agli array: un array richiede
un blocco di memoria contigua che se è molto grande e la memoria
è frammentata potrebbe non essere disponibile, mentre una lista per gli stessi elementi
richiede tanti blocchi piccoli che potrebbero esserci anche se la memoria
è molto frammentata. Rappresentazione in memoria:
--------- --------- --------- --------- ---------
| | | | | | | | | | | | | | |
| | •------>| | •------>| | •------>| | •------> . . .| | • |
| | | | | | | | | | | | | | |
--------- --------- --------- --------- ---------
L'accesso agli elementi in un array è molto più veloce che in una lista.
Operazioni fondamentali sulle liste, relativamente a liste di interi:
#include <stdlib.h>
typedef struct Elem {
int val;
struct Elem *next;
} Elem, *List;
List add_head(List L, int val) {
Elem *newelem = malloc(sizeof(Elem));
newelem->val = val;
newelem->next = L;
return newelem;
}
List add_tail(List L, int val) {
Elem *newelem = malloc(sizeof(Elem));
newelem->val = val;
newelem->next = NULL;
if (L == NULL) return newelem;
Elem *e = L;
while (e->next != NULL)
e = e->next;
e->next = newelem;
return L;
}
Elem *find(List L, int val) {
Elem *e = L;
while (e != NULL && e->val != val)
e = e->next;
return e;
}
List remove(List L, int val) {
if (L == NULL) return NULL;
if (L->val == val) {
List newHead = L->next;
free(L);
return newHead;
}
Elem *prec = L;
while (prec->next != NULL && (prec->next)->val != val)
prec = prec->next;
if (prec->next != NULL) {
Elem *del = prec->next;
prec->next = (prec->next)->next;
free(del);
}
return L;
}
Esercizio 30
Scrivere una funzione
List insord(List L, int val)
che inserisce un nuovo elemento con
valore
val
nella lista ordinata (in senso crescente)
L
, mantenendo l'ordinamento.
Ritorna il puntatore alla lista dopo l'inserimento. Ad es., se
L
è la lista
1 -> 3 -> 6 -> 8
e
val = 5
allora la funzione modifica la lista
così
1 -> 3 -> 5 -> 6 -> 8
.
Esercizio 31
Scrivere una funzione
List reverse(List L)
che inverte la lista
L
e ritorna il puntatore
alla lista invertita. Ad es., se
L
è la lista
1 -> 2 -> 3 -> 4
allora la funzione
la trasforma così
4 -> 3 -> 2 -> 1
.
Esercizio 32
Implementare il modulo di memorizzazione (file
archivio_mem.c
) tramite liste.