Fonctions de bibliothèque C -feof()

Bibliothèque standard C - <stdio.h>

feof()Utilisée pour détecter si le fichier a déjà été lu jusqu'à la fin.

On peut le considérer comme un « détecteur de fin » — chaque fois que vous finissez de lire une partie du contenu, vous lui demandez : « Avons-nous atteint la fin ? »


Description

Fonctions de bibliothèque Cint feof(FILE *stream)Teste l'indicateur de fin de fichier du flux donné.

Deux nouveaux concepts apparaissent ici ; laissez-moi d'abord les expliquer séparément :

fluxC'est une abstraction des entrées/sorties en langage C. Qu'il s'agisse d'un fichier sur un disque dur, d'une saisie au clavier ou de données réseau, en C, tout est uniformément traité comme un « flux ». Vous pouvez imaginer un flux comme un tuyau d'eau, avec les données circulant d'une extrémité à l'autre.

Indicateur de fin de fichier (marqueur EOF)C'est un indicateur d'état interne porté par chaque flux de fichier. Il est comme un signet qui se tourne automatiquement vers la page « fin de lecture » lorsque le contenu du fichier a été entièrement lu.

Le but de feof() est de vérifier ce signet — si le signet indique « fin de lecture », feof() renvoie une valeur non nulle. Si le signet est encore à « lecture non terminée », feof() renvoie 0.


Déclaration

Voici la déclaration de la fonction feof() ; décomposons sa signification partie par partie :

int feof(FILE *stream)

intC'est le type de retour — feof() renvoie un entier ; non nul signifie que la fin a été atteinte, 0 signifie qu'elle ne l'a pas été.

FILE *streamCeci est le paramètre — vous devez passer un pointeur de fichier (le pointeur renvoyé par fopen() lors de l'ouverture du fichier) pour indiquer à feof() quel flux de fichier vérifier.


Paramètre

feof() prend un paramètre :

ParamètreTypeDescription
fluxFILE *Pointeur de fichier, renvoyé par la fonction fopen(), pointant vers le fichier ouvert à vérifier.

Valeur de retour

La valeur de retour est décrite comme suit :

Valeur de retourSignification
valeur non nulleLe fichier a été lu jusqu'à la fin ; il n'y a plus de contenu à lire.
0Le fichier n'a pas encore été entièrement lu, la lecture peut donc continuer

Point clé : feof() ne renvoie une valeur non nulle qu'après « avoir tenté de lire au-delà de la fin du fichier ». Si vous venez de lire le dernier caractère mais que vous n'avez pas encore essayé de continuer la lecture, feof() renvoie toujours 0. Ce problème de timing sera expliqué en détail dans la section suivante.


Exemple

L'exemple suivant montre l'utilisation correcte de la fonction feof().

Le programme lit le contenu du fichier caractère par caractère, et chaque fois qu'il lit un caractère, il utilise feof() pour vérifier si la fin a été atteinte.

Exemple

#include <stdio.h>

int main ()
{
   // FILE * est un type de pointeur de fichier, utilisé pour pointer vers un fichier ouvert
   FILE *fp;
   // fgetc() renvoie int au lieu de char, car il peut avoir besoin de renvoyer EOF (-1)
   int c;

   // fopen() ouvre un fichier, "r" indique le mode lecture seule (lecture)
   fp = fopen("file.txt","r");
   // Si le fichier n'existe pas ou si la permission est refusée, fopen() renvoie NULL
   if(fp == NULL)
   {
      // perror() affiche les messages d'erreur système pour aider à localiser le problème
      perror("Error opening file");
      return(-1);
   }

   // Utilisez une boucle infinie + des vérifications internes
   // Cela garantit de "lire d'abord, puis vérifier", ce qui évite de lire du contenu supplémentaire
   while(1)
   {
      // Étape 1 : Lire un caractère depuis le fichier
      c = fgetc(fp);
      // Étape 2 : Immédiatement après la lecture, utilisez feof() pour vérifier si la fin a été atteinte
      if( feof(fp) )
      {
          // Si la fin est atteinte, sortez de la boucle et arrêtez de traiter c
          break ;
      }
      // Étape 3 : N'utilisez la valeur de c qu'après avoir confirmé que la fin n'a pas été atteinte
      printf("%c", c);
   }

   // fclose() ferme le fichier et libère les ressources système
   fclose(fp);
   return(0);
}

Supposons que nous ayons un fichier textefile.txt, dont le contenu est le suivant :

这里是 example.com

Compilez et exécutez le programme ci-dessus, la sortie est :

这里是 example.com

Le programme a correctement imprimé tout le contenu du fichier, sans aucun caractère parasite supplémentaire.


Piège courant : pourquoi vous ne pouvez pas mettre feof() dans la condition de boucle

De nombreux débutants écrivent le style de code suivant, qui semble plus concis, mais qui est en réalité incorrect :

Exemple incorrect

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   if(fp == NULL)
   {
      perror("Error opening file");
      return(-1);
   }

   // Incorrect : utiliser feof() comme condition d'entrée de boucle
   while( !feof(fp) )
   {
      c = fgetc(fp);
      printf("%c", c);
   }

   fclose(fp);
   return(0);
}

La sortie de ce code incorrect serait :

这里是 example.com

Il y a un caractère parasite supplémentaire à la fin. Pourquoi cela ? Traçons ci-dessous le processus d'exécution de la boucle, tour à tour :

Itérations de la boucleEntrée de boucle feof()fgetc() litSorties de printf()Description
Tour 1Renvoie 0 (pas encore lu)'这'这normal
Tour 2Renvoie 0 (pas encore à la fin)'里'里normal
............Les caractères du milieu s'affichent normalement
Dernier tourRenvoie 0 (pas encore à la fin)'m'mLe dernier caractère normal
Un tour supplémentaireRenvoie 0 (Remarque ! À ce stade, 'm' vient d'être lu, et feof ne sait pas encore que la fin a été atteinte.)EOF(-1)(caractères illisibles)Bug ! Lecture une fois de trop

La racine du problème est la suivante : lorsque vous venez de lire 'm' (le dernier caractère du fichier), feof() renvoie encore 0.

Il doit attendre que vous « essayiez de lire une fois de plus » et découvriez qu'il n'y a plus de contenu à lire, et c'est seulement alors qu'il fera basculer le drapeau interne sur « terminé ».

Donc le motif while(!feof(fp)) fait exécuter à la boucle une itération supplémentaire. Dans cette itération supplémentaire, fgetc() renvoieEOF(-1), printf tente d'imprimer -1 comme un caractère, ce qui produit une sortie brouillée.

Une phrase à retenir :feof() est un « rapport après coup », pas un « avertissement préalable »EOF. Il répond à « si la fin a été atteinte lors de la dernière lecture », et non à « si la fin sera atteinte lors de la prochaine lecture ». N'utilisez donc jamais feof() comme condition d'entrée d'une boucle.

Le bon motif est l'approche de l'exemple précédent : lire d'abord, puis vérifier, et n'utiliser le contenu lu qu'après avoir confirmé qu'il est sûr.


Quand utiliser feof()

feof() est principalement utilisé dans les deux scénarios suivants :

ScénariosUtilisationExemple
Lire un fichier dans une boucleLire d'abord, puis vérifier (recommandé)while(1) { c = fgetc(fp); if(feof(fp)) break; ... }
Dépannage des erreurs de lectureDistinguer entre « arrêt normal » et « erreur de lecture »if(feof(fp)) { /* lecture terminée normalement */ } else if(ferror(fp)) { /* erreur de lecture */ }

Dans le second scénario, le retour de EOF par fgetc() a deux possibilités : soit le contenu a réellement été entièrement lu (déterminé avec feof()), soit une erreur s'est produite pendant la lecture (déterminée avec ferror()). Il faut distinguer les deux et les traiter séparément.

Bibliothèque standard C - <stdio.h>

autres extensions