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 dichar
non serve la&
)
- ricorda che per estrarre una stringa con
- viene chiamata la funzione
notturno
, la quale restituisce1
oppure0
(cioè vero oppure falso) se l'orario indicato dal parametroh
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.