Stazione di monitoraggio 1 - Soluzione

Il tipo di richieste formulate nel problema suggerisce la possibilità di effettuare l'elaborazione delle righe durante la lettura del file. In particolare, non serve caricare in memoria tutti i dati per farne l'elaborazione. Pertanto verranno lette le righe nel file una ad una, e ciascuna riga letta verrà subito elaborata per svolgere i calcoli necessari.

In pratica, l'intera elaborazione - o quasi - del file viene svolta nella funzione di lettura elabora_file seguente:

void elabora_file(FILE *f)
{
    char buf[1000];
    int n;                 // numero di righe lette
    int nconv;             // numero di elementi convertiti
    float max_temp;        // temperatura massima
    int aa, MM, gg;        // data
    int hh, mm, ss, ms;    // orario
    char id[11];           // identificativo del dispositivo
    float temp;            // temperatura
    int umid;              // umidità
    float vel;             // velocità del vento

    puts("[NOTTURNO]");
    n = 0;
    max_temp = -300.0;
    /* ogni ciclo legge una riga dal file */
    while (fgets(buf, sizeof(buf), f)) {
        /* conversione dei dati contenuti nella riga letta */
        nconv = sscanf(buf, "%d-%d-%d %d:%d:%d.%d %s %f %d%% %f",
            &aa, &MM, &gg,
            &hh, &mm, &ss, &ms,
            id, &temp, &umid, &vel);

        /* i dati completi sono 11;
         * se sono di meno è una riga vuota
         */
        if (nconv != 11) continue;
        /* tiene traccia della temperatura massima */
        if (temp > max_temp) max_temp = temp;
        /* stampa la riga corrente se in fascia notturna */
        if (notturno(hh)) printf("%s", buf);
        /* incrementa il numero di righe lette correttamente */
        n++;
    }
    /* stampa i risultati */
    printf("\n[MAX-TEMP]\n%.1f\n", max_temp);
    printf("\n[RIGHE]\n%d\n", n);
}

La funzione è ben commentata, e dovrebbe essere semplice seguirne la logica.

La funzione richiede un solo argomento: il file da leggere f, già aperto in lettura tramite fopen prima di chiamare elabora_file (S8.2.1).

Nella funzione elabora_file:

  • il file viene letto con un ciclo attraverso fgets (S8.6);
  • da ogni riga, si estraggono i dati utili tramite sscanf, e si memorizzano in variabili locali alla funzione;
    • ricorda che per estrarre una stringa con sscanf si usa lo specificatore %s (S8.6!
    • nella sscanf, la variabile stringa nella quale memorizzare il nome estratto va passato per riferimento (e visto che si tratta di un vettore di char non serve la &)
  • viene chiamata la funzione notturno, la quale restituisce 1 oppure 0 (cioè vero oppure falso) se l'orario indicato dal parametro h corrisponde ad un orario notturno o meno; in tal caso, per semplicità , viene stampata direttamente la stringa caricata da file.

La funzione notturno può essere implementata come segue:

int notturno(int h)
{
    if ((h >= 22) || (h <= 5)) return 1;
    return 0;
}

Infine, un esempio di main che utilizza le varie funzioni è il seguente:

int main(int argc, const char *argv[])
{
    FILE *infile;

    /* termina se il numero di parametri è errato */
    if (argc != 2)
        return 1;

    /* apre il file in lettura */
    infile = fopen(argv[1], "r");
    /* termina in caso di errore */
    if (infile == NULL) {
        fprintf(stderr, "# Errore apertura file\n");
        return 1;
    }
    elabora_file(infile);
    fclose(infile);

    return 0;
}

La parte più interessante è l'uso della funzione fopen per aprire il file (vedi S8.2.1) Il nome del file da leggere sarà l'argomento argv[1] del main (vedi S6.9).

In caso di errore nell'apertura del file, per esempio se il file con il nome specificato non esiste, la fopen restituisce NULL. In tal caso, il programma termina senza proseguire con l'elaborazione, stampando un messaggio di errore tramite la fprintf. Questa funzione, illustrata in S8.7, stampa il messaggio sul file standard stderr, chiamato standard error (vedi S8.2.3). Lo standard error è un file associato al terminale; ovvero, quando viene scritto, il testo viene visualizzato a video. È un file comunemente utilizzato per i messaggi di errore o avvertimento.

Se invece il file viene aperto correttamente, viene chiamata la funzione elabora_file illustrata precedentemente.

Infine, il file viene chiuso con fclose prima di terminare il programma.