Rilevazione errori

Oltre alla fine del file, esistono altri errori possibili quando si cerca di leggere da file. Alcuni errori sono dovuti per esempio a problemi di livello hardware, altri a livello di sistema operativo, ecc. Di questo tipo di errori non ci interessiamo.

Un errore di cui invece parliamo è il fallimento di conversione. Quando si cerca di leggere da file un intero, la funzione fscanf deve convertire una stringa in intero. Infatti, un file di testo è una sequenza di caratteri, ossia una stringa. Se vogliamo un intero, dobbiamo convertire i caratteri che si trovano su file in un intero.

Questa conversione non è sempre possibile. Si pensi per esempio alla situazione in cui su file sono memorizzati i caratteri abe mds. Questa sequenza non corrisponde a nessun intero. Se si cerca di leggere un intero, deve essere possibile capire che la conversione da stringa a intero è fallita.

Errori di questo genere si riflettono sul valore di ritorno della funzione fscanf. Questa funzione, in generale, può leggere più di un oggetto per volta. Per esempio, può leggere, con una chiamata sola, un intero, una stringa, e un reale. Il valore di ritorno della funzione è il numero di oggetti che sono è stato possibile convertire. Il valore EOF viene ritornato solo nel caso in cui si è incontrata la fine del file prima ancora di riuscire a convertire anche un solo intero.

la funzione fscanf ritorna il numero di oggetti che è stato possibile leggere (convertire da stringa al tipo dell'oggetto), oppure EOF se il file è finito prima di poter leggere il primo oggetto.

Esempio:

fscanf(fd, "%d %d", &x, &y); ha i seguenti possibili valori di ritorno:

2
sono stati letti (convertiti con successo) due interi, memorizzati nell varabili x e y;
1
un solo intero è stato letto con successo, ed è stato memorizzato nella variabile x; non è stato possibile leggere il secondo intero: questo può essere dovuto al fallimento di conversione (quello che sta scritto su file non si può convertire in intero), oppure al fatto che è stata incontrata la fine del file;
0
non è stato possibile leggere nessuno dei due numeri interi: questo è dovuto alla presenza di caratteri non interpretabili come interi su file;
EOF
nessun intero è stato letto da file, perchè si è incontrata la fine del file prima ancora di riuscire a leggere il primo intero.

Si noti che, se il risultato è 1, allora non è possibile capire se il problema è stato un errore di conversione oppure la fine del file. Per il momento, questo fatto non ci interessa, visto che leggiamo sempre un unico elemento per volta. Nel caso in cui la fscanf viene usata per leggere da file il valore di una sola variabile, allora i possibili valori di ritorno sono:

fscanf(fd, "%d", &x);

1
un intero è stato letto e memorizzato in x;
0
non è stato possibile leggere l'intero, perchè quello che sta scritto su file non è interpretabile come un intero;
EOF
si è incontrata la fine del file prima di poter leggere un intero da memorizzare in x.

Da questa schema è chiaro che, nel caso di lettura di un solo intero, è sempre possibile capire quale errore si è verificato semplicemente guardando il valore di ritorno della funzione fscanf.

Il programma arrayerr.c è l'ultima versione del programma di lettura di un array da file. Questa volta è stato aggiunto un controllo sulla lettura: se la conversione in intero è fallita allora la funzione fscanf ritorna il valore 0, e in questo caso il programma termina.

/*
  Legge un array da file fino all'eof.
Salta le cose che non riesce a leggere.
*/

#include<stdlib.h>
#include<stdio.h>

int main() {
  int n;
  int vett[100];
  FILE *fd;
  int res;
  int i;

		/* apre il file */
  fd=fopen("arrayerr.txt", "r"); 

		/* verifica errori in apertura */
  if( fd==NULL ) {
    perror("Errore in apertura del file");
    exit(1);
  }

  
		/* legge l'array */
  for(n=0; n<=99; n++) {
    res=fscanf(fd, "%d", &vett[n]);
    if( res==EOF )
      break;
    else if( res==0 ) {
      printf("Non riesco a leggere un intero da file\n");
      exit(1);
    }
  }


		/* stampa l'array */
  for(i=0; i<=n-1; i++)
    printf("%d\n", vett[i]);

		/* chiude il file */
  fclose(fd);

  return 0;
}

Nel caso in cui non interessa stabilire quale particolare errore si è verificato, basta controllare che il valore di ritorno della funzione fscanf coincida con il numero di elementi che doveva leggere (in questo caso, uno), e generare un messaggio di errore in caso contrario.