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.