Note:

Inserire ampiamente commenti  all'interno del sorgente prodotto. Per il nome del file utilizzare la sintassi:

grXX_4a.c        dove XX è il numero del gruppo (es. 01, 05, 45, 64, etc).

Quindi, ad esempio,  il gruppo numero 6 dovrà inviare per mail al docente un file nominato:

gr06_4a.c

In caso di dubbio circa autori e/o autenticità del materiale sottomesso, il docente si riserva il diritto di effettuare verifiche ed eventualmente di annullare gli elaborati.

AGGIORNAMENTO

In merito al problema riscontrato da diversi gruppi nella gestione del file 'rubrica' utilizzato nel progetto, c'è da tenere conto del fatto che in molte implementazioni i file "binari" devono essere aperti in lettura, scrittura o aggiornamento utilizzando l'opzione 'b'. Consiglio quindi di aprire (se il compilatore lo consente) il file in scrittura o modifica utilizzando l'opzione "wb" o "rb+": in questo modo il programma dovrebbe funzionare correttamente nei richiami di fread() e fwrite().

Esercizio:

Scrivere un programma per la gestione di una rubrica telefonica memorizzata su file.
Definire a tal proposito una struttura di questo tipo:

struct scheda{
  char cognome[ 15 ];
  char nome[ 15 ];
  char telefono[ 15 ];
  int prossimo;
};

Il file utilizzato per memorizzare i record della rubrica dovrà essere gestito ad accesso casuale (record a dimensione fissa) e dovrà avere il seguente formato.

      
                lista   lista  numero
                record  record record  record  record   .....    record
                attivi  vuoti  totali   n. 1    n. 2              n. M
                 (int)  (int)  (int)  (scheda)(scheda)          (scheda)
               _________________________________________.....____________
               |__LR__|__LV__|__NT__|________|________|_.....__|________|         
               ^
               |
inizio file ___|
  (fp)

In un certo istante, supponendo che nel file siano presenti M record, come  nello schema di sopra, i primi tre campi del file, tutti di dimensione pari  ad un int, dovranno contenere rispettivamente la posizione all'interno del  file (valori da 1 a M) del primo elemento della lista dei record attivi (LR),  la posizione (valori da 1 a M) del primo elemento della lista dei record liberi (LV) e il numero totale M di record (NT), sia attivi che liberi, presenti nel file. In Particolare:

LISTA RECORD ATTIVI
LISTA RECORD VUOTI
    Supponendo che il campo LR, LV, o il campo prossimo di qualunque dei  record memorizzati nel file contenga un certo valore N (relativo alla posizione  all'interno del file di un record referenziato da uno di questi tre campi),  per determinare l'indirizzo fisico (in byte) del record referenziato sarà sufficiente calcolare:

offset =  3 * sizeof(int) + (N-1) * sizeof (scheda)
          |______________|   |_____________________|
           salto i 3 campi     salto gli N-1 record
            LR, LV, NT              precedenti

e utilizzare tale offset per posizionare il puntatore a file nel punto dove inizia tale record mediante la funzione fseek().
   
Il  programma dovrà prevedere delle funzioni di inserimento, cancellazione e stampa di record.

INSERIMENTO
Tale funzione dovrà richiedere in input i dati della nuova scheda da inserire. A questo punto l'inserimento di un nuovo record all'interno del file avverrà:

Una volta inserito 'fisicamente' il record, dovrà essere aggiornato il campo "prossimo" dei record interessati al fine di gestire l'ordinamento logico delle varie schede inserite (questo per ottimizzare la funzione di ricerca di una data scheda). Quindi si dovrà:
In sostanza il campo prossimo della struttura (valori compresi tra 1 e M se nell'istante considerato ho M record nel file) dovrà essere utilizzato e gestito per garantire l'ordinamento, esattamente come nel caso del campo "prossimo" della struttura "nodo" vista a lezione per gestire le liste.

STAMPA
Tale funzione dovrà stampare su video le informazioni correnti relative all'archivio: campo LR, LV, NT e, formattati in modo tabellare, i vari record attivi secondo l'ordinamento per cognome (seguendo quindi l'informazione del campo prossimo e utilizzandola per posizionarsi fisicamente sul record seguente) nella forma COGNOME, NOME, TELEFONO, PROSSIMO.

CANCELLAZIONE
Tale funzione dovrà richiedere in input un cognome e scandire i record secondo l'ordinamento logico relativo a tale campo (seguendo quindi l'informazione del campo prossimo e utilizzandola per posizionarsi fisicamente sul record seguente), cancellando le informazioni della scheda associata nel caso in cui questa venga trovata o stampando un messaggio informativo nel caso tale scheda non sia presente nell'archivio.
La cancellazione dall'archivio dovrà essere fatta nel seguente modo:
Utilizzare, oltre alle funzioni di printf(), scanf() per la stampa di messaggi e l'input dei campi da inserire, le funzioni: