102 votes

Utilisation de fflush(stdin)

Alors, une recherche rapide sur Google pour fflush(stdin) pour vider le tampon d'entrée révèle de nombreux sites web mettant en garde contre son utilisation. Et pourtant, c'est exactement ainsi que mon professeur de CS a appris à la classe à le faire.

Est-ce si mauvais d'utiliser fflush(stdin)? Devrais-je vraiment m'abstenir de l'utiliser, même si mon professeur l'utilise et que cela semble fonctionner parfaitement?

93voto

Eli Bendersky Points 82298

Simple : il s'agit d'un comportement indéfini, car fflush est censé être appelé sur un flux de sortie. Voici un extrait de la norme C :

int fflush(FILE *ostream);

ostream pointe vers un flux de sortie ou un flux de mise à jour dans lequel la dernière opération n'était pas une entrée, la fonction fflush provoque l'envoi de toutes les données non écrites pour ce flux à l'environnement hôte pour qu'elles soient écrites dans le fichier ; sinon, le comportement est indéfini.

Il ne s'agit donc pas de savoir "à quel point" c'est mauvais. fflush(stdin) n'est tout simplement pas portable, donc vous ne devriez pas l'utiliser si vous voulez que votre code soit portable entre les compilateurs.

24voto

parrowdice Points 121

Selon la norme, fflush ne peut être utilisé qu'avec des tampons de sortie, et évidemment stdin n'en est pas un. Cependant, certaines bibliothèques C standard fournissent l'utilisation de fflush(stdin) en tant qu'extension. Dans ce cas, vous pouvez l'utiliser, mais cela affectera la portabilité, donc vous ne pourrez plus utiliser n'importe quelle bibliothèque C standard conforme aux normes sur terre et attendre les mêmes résultats.

16voto

Steve Summit Points 16971

Je crois que vous ne devriez jamais appeler fflush(stdin), et pour la simple raison que vous ne devriez même pas trouver nécessaire d'essayer de vider l'entrée en premier lieu. En réalité, il n'y a qu'une seule raison pour laquelle vous pourriez penser que vous deviez vider l'entrée, et c'est : pour contourner une mauvaise saisie sur laquelle scanf est bloqué.

Par exemple, vous pourriez avoir un programme qui se trouve dans une boucle lisant des entiers en utilisant scanf("%d", &n). Assez vite, vous découvrirez que la première fois que l'utilisateur tape un caractère non numérique comme 'x', le programme entre dans une boucle infinie.

Face à cette situation, je pense que vous avez essentiellement trois choix :

  1. Vider l'entrée de quelque manière que ce soit (si ce n'est pas en utilisant fflush(stdin), alors en appelant getchar dans une boucle pour lire des caractères jusqu'à \n, comme cela est souvent recommandé).
  2. Dire à l'utilisateur de ne pas taper de caractères non numériques lorsque des chiffres sont attendus.
  3. Utiliser quelque chose d'autre que scanf pour lire l'entrée.

Maintenant, si vous êtes débutant, scanf semble être le moyen le plus simple de lire l'entrée, et donc le choix n°3 semble effrayant et difficile. Mais le n°2 semble être un moyen facile, car tout le monde sait que les programmes informatiques peu conviviaux sont un problème, donc ce serait bien de faire mieux. Ainsi, beaucoup trop de programmeurs débutants se retrouvent coincés, sentant qu'ils n'ont d'autre choix que de faire n°1. Ils doivent plus ou moins saisir l'entrée en utilisant scanf, ce qui signifie qu'elle restera bloquée sur une mauvaise saisie, ce qui signifie qu'ils doivent trouver un moyen de vider la mauvaise saisie, ce qui les incite fortement à utiliser fflush(stdin).

J'aimerais encourager tous les débutants en programmation C là-bas à faire un ensemble différent de compromis :

  1. Pendant les premières étapes de votre carrière en programmation C, avant d'être à l'aise avec tout autre chose que scanf, ne vous préoccupez simplement pas de la mauvaise saisie. Vraiment. Allez-y et utilisez le moyen facile n°2 ci-dessus. Pensez-y de cette manière : vous êtes débutant, il y a beaucoup de choses que vous ne savez pas encore faire, et l'une des choses que vous ne savez pas encore faire est : faire face gracieusement à une saisie inattendue.

  2. Dès que vous le pouvez, apprenez à saisir l'entrée en utilisant des fonctions autres que scanf. À ce moment-là, vous pouvez commencer à traiter de manière élégante la mauvaise saisie, et vous disposerez de nombreuses autres techniques bien meilleures qui ne nécessiteront pas d'essayer de "vider la mauvaise saisie" du tout.

Ou, en d'autres termes, les débutants qui sont toujours coincés en utilisant scanf devraient se sentir libres d'utiliser le moyen facile n°2, et quand ils seront prêts, ils devraient passer de là à la technique n°3, et personne ne devrait utiliser la technique n°1 pour essayer de vider l'entrée du tout -- et certainement pas avec fflush(stdin).

9voto

Steve Summit Points 16971

Utiliser fflush(stdin) pour vider l'entrée est un peu comme chercher de l'eau avec un bâton en forme de lettre "S".

Et aider les gens à vider l'entrée d'une manière "meilleure" revient un peu à se précipiter vers un radiesthésiste en forme de S et dire "Non, tu te trompes, tu dois utiliser un bâton en forme de Y !".

En d'autres termes, le vrai problème n'est pas que fflush(stdin) ne fonctionne pas. Appeler fflush(stdin) est un symptôme d'un problème sous-jacent. Pourquoi devez-vous "vider" l'entrée en premier lieu ? C'est là que se situe votre problème.

Et généralement, ce problème sous-jacent vient du fait que vous utilisez scanf, dans l'une de ses modes peu utiles qui laissent inopinément des sauts de ligne ou d'autres textes "indésirables" dans l'entrée. La meilleure solution à long terme est donc d'apprendre à faire de l'entrée en utilisant de meilleures techniques que scanf, afin de ne pas avoir à gérer ses entrées non traitées et d'autres bizarreries.

5voto

Zack Points 44583

Aucune des réponses existantes ne souligne un aspect clé du problème.

Si vous vous trouvez vouloir "vider le tampon d'entrée", vous êtes probablement en train d'écrire un programme interactif en ligne de commande, et il serait plus précis de dire que ce que vous voulez est de supprimer les caractères de la ligne d'entrée actuelle que vous n'avez pas encore lus.

Ce n'est pas ce que fait fflush(stdin). Les bibliothèques C qui prennent en charge l'utilisation de fflush sur un flux d'entrée le documentent comme faisant rien, ou comme étant en train de supprimer des données mises en mémoire tampon qui ont été lues depuis le fichier sous-jacent mais non transmises à l'application. Cela peut facilement être soit plus soit moins d'entrée que le reste de la ligne actuelle. Il fonctionne probablement par accident dans de nombreux cas, car le pilote de terminal (dans son mode par défaut) fournit l'entrée à un programme interactif en ligne de commande une ligne à la fois. Cependant, dès que vous essayez de fournir des entrées à votre programme à partir d'un fichier réel sur disque (peut-être pour des tests automatisés), le noyau et la bibliothèque C passeront à la mise en mémoire tampon de données par gros "blocs" (souvent de 4 à 8 ko) sans rapport avec les limites des lignes, et vous vous demanderez pourquoi votre programme traite la première ligne du fichier puis passe plusieurs dizaines de lignes et reprend au milieu d'une ligne apparemment aléatoire ci-dessous. Ou si vous décidez de tester votre programme sur une ligne très longue tapée à la main, alors le pilote de terminal ne pourra pas donner au programme toute la ligne d'un seul coup et fflush(stdin) n'en sautera pas tout.

Que devriez-vous faire à la place? L'approche que je préfère est, si vous traitez les entrées une ligne à la fois, alors lire une ligne entière d'un coup. La bibliothèque C a des fonctions spécifiques pour cela : fgets (en C90, donc entièrement portable, mais vous oblige quand même à traiter les très longues lignes par morceaux) et getline (spécifique à POSIX, mais gérera un tampon malloc pour vous permettre de traiter les longues lignes en une seule fois quel que soit leur longueur). Il y a généralement une traduction directe du code qui traite "la ligne actuelle" directement depuis stdin en code qui traite une chaîne contenant "la ligne actuelle".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X