Lezione 20
Discussione esercizio 37:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/* È uguale alla funzione next_word() del programma che conta le parole distinte
 * in cui getchar() è stato sostituito da fgetc(f). */
char *fnext_word(FILE *f) {
    char *w = NULL;
    int c, n = 0;
    do {
        c = fgetc(f);
        if (isalpha(c)) {
            w = realloc(w, n + 2);
            w[n++] = c;
        }
    } while (c != EOF && (n == 0 || isalpha(c))) ;
    if (w != NULL) w[n] = '\0';
    return w;
}

//Confronta due stringhe (parole) per qsort
int wcmp(const void *e1, const void *e2) {
    char *w1 = *(char **)e1, *w2 = *(char **)e2;
    return strcmp(w1, w2);
}

int main(int argc, char *argv[]) {
    if (argc != 3) return 0;
    FILE *fin = fopen(argv[1], "r");    //Apre il primo file in lettura
    FILE *fout = fopen(argv[2], "w");   //Apre il secondo file in scrittura
    if (fin == NULL || fout == NULL) {
        printf("Impossibile aprire i files\n");
        return 0;
    }
    char **wA = NULL, *w;
    int i, nw = 0;
    while ((w = fnext_word(fin)) != NULL) {           //Legge le parole dal primo file
        wA = realloc(wA, (nw + 1)*sizeof(char *));    //e le copia in un array dinamico
        wA[nw++] = w;
    }
    qsort(wA, nw, sizeof(char *), wcmp);              //Ordina le parole
    int wcount = 0;
    for (i = 0 ; i < nw ; i++) {    //Scrive nel secondo file le parole distinte e
        wcount++;                   //per ognuna il numero di occorrenze
        if (i == nw - 1 || strcmp(wA[i], wA[i + 1]) != 0) {
            fprintf(fout, "%5d  %s\n", wcount, wA[i]);
            wcount = 0;
        }
        free(wA[i]);
    }
    free(wA);
    fclose(fin);
    fclose(fout);
    printf("Numero parole: %d\n", nw);
    return 0;
}
Discussione esercizio 38:
#include <stdio.h>

//Concatena due files, appendendo il contenuto del secondo file al primo.
int main(int argc, char *argv[]) {
    if (argc != 3) return 0;
    FILE *f1 = fopen(argv[1], "a");    //Apre il primo file in append
    FILE *f2 = fopen(argv[2], "r");    //Apre il secondo file in lettura
    if (f1 == NULL || f2 == NULL) {
        printf("Impossibile aprire uno dei files!\n");
        return 0;
    }
    int c;
    while ((c = fgetc(f2)) != EOF)    //Legge carattere per carattere il secondo file
        fputc(c, f1);                 //e appende i caratteri al primo file
    fclose(f1);
    fclose(f2);
    return 0;
}
Funzioni per il posizionamento del cursore dei files aperti. Uso delle funzioni ftell() e fseek() in una funzione che cerca la prima occorrenza di una stringa in un file di testo:
#include <stdio.h>
#include <string.h>

/* Cerca la prima occorrenza della stringa str nel file di testo f a partire 
 * dalla posizione corrente. Se la trova ritorna la posizione (data da ftell()), 
 * altrimenti ritorna -1.
 * Usa fgets() per leggere un blocco di caratteri di lunghezza uguale alla 
 * lunghezza della stringa e poi usa fseek() e fgetc() per riposizionarsi per la 
 * prossima chiamata di fgets(). */
long filefind(FILE *f, char *str) {
    long n = strlen(str) + 1, pos = ftell(f);
    char buffer[n];
    while (fgets(buffer, n, f) != NULL) {
        if (strcmp(buffer, str) == 0)
            return pos;
        else {
            fseek(f, pos, SEEK_SET);
            fgetc(f);
            pos = ftell(f);
        }
    }
    return -1;
}

//Legge dalla linea di comando il nome di un file e una stringa da cercare
int main(int argc, char *argv[]) {    
    if (argc != 3) return 0;
    FILE *f = fopen(argv[1], "r");
    if (f == NULL) {
        printf("Impossibile aprire file \"%s\"\n", argv[1]);
        return 0;
    }
    long pos = filefind(f, argv[2]);
    if (pos >= 0)
        printf("Trovata in posizione %ld\n", pos);
    else
        printf("Non trovata\n");
    fclose(f);
    return 0;
}

Funzioni per leggere e scrivere file binari: Implementazione del modulo di memorizzazione del programma che gestisce un archivio di dipendenti tramite file binari (uso di fread(), fwrite() e fseek()).
/**************************** FILE archivio_mem.c *****************************/
/* Implementazione del modulo di memorizzazione del programma archivio tramite 
 * file binario. Ogni struct Dipendente è memorizzata nel file così com'è
 * rappresentata in memoria. Tale rappresentazione non è, in generale,
 * portabile: il file potrebbe non essere letto in modo corretto dallo stesso
 * programma compilato su un'altra piattaforma. 
 * L'archivio non è copiato in memoria ma è letto e scritto direttamente su
 * disco. */
#include "archivio_mem.h"
#include <stdlib.h>
#include <stdio.h>

#define NOMEARCH    "ArchivioDipendenti"

static FILE *archivio = NULL;
static int numDipendenti = 0;

void open_archivio() {
    archivio = fopen(NOMEARCH, "r+b");        //Apre il file binario in lettura e scrittura
    if (archivio == NULL)                     //Se non esiste,
        archivio = fopen(NOMEARCH, "w+b");    //lo crea
    if (archivio == NULL) {
        printf("ERRORE in apertura archivio\n");
        exit(1);
    }
    Dipendente d;                                   //Legge il file archivio, per
    while (fread(&d, sizeof(Dipendente), 1, archivio) == 1)   //determinare il numero
        numDipendenti++;                                      //dei dipendenti
}

void add_dipendente(Dipendente d) {
    fseek(archivio, numDipendenti*sizeof(Dipendente), SEEK_SET);    //Va alla fine del file
    fwrite(&d, sizeof(Dipendente), 1, archivio);                    //e scrive il nuovo record
    fflush(archivio);                 //Svuota il buffer del file
    numDipendenti++;
}

int num_dipendenti() {
    return numDipendenti;
}

Dipendente get_dipendente(int i) {
    Dipendente d;
    fseek(archivio, i*sizeof(Dipendente), SEEK_SET);    //Va all'i-esimo record
    fread(&d, sizeof(Dipendente), 1, archivio);         //e lo legge
    return d;
}

void close_archivio() {
    fclose(archivio);
    archivio = NULL;
    numDipendenti = 0;
}

Esercizio 39    Scrivere un funzione int filenumocc(FILE * f, char *s) che ritorna il numero di occorrenze della stringa s nel file di testo f.
Esercizio 40    Scrivere un programma che prende come argomento il nome di un file e se non esiste lo crea e vi scrive il primo milione di numeri primi (in ordine crescente). Poi permette all'utente di inserire interi k e per ogni k stampa il k-esimo numero primo, leggendolo dal file. Il file è binario e i numeri primi sono memorizzati come int. Ad esempio, se l'utente inserisce k = 1 il programma stampa 2, se k = 1000 il programma stampa 7919 e se k = 1000000 il programma stampa 15485863 (il milionesimo numero primo).