120 votes

Comment effacer le tampon d'entrée en C ?

J'ai le programme suivant :

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

Comme l'a expliqué l'auteur du code ci-dessus : Le programme ne fonctionnera pas correctement parce qu'à la ligne 1, lorsque l'utilisateur appuiera sur Entrée, il laissera dans le tampon d'entrée 2 caractères : Enter key (ASCII code 13) y \n (ASCII code 10) . Par conséquent, à la ligne 2, on lira le texte suivant \n et n'attendra pas que l'utilisateur entre un caractère.

OK, j'ai compris. Mais ma première question est la suivante : pourquoi la deuxième getchar() ( ch2 = getchar(); ) ne lit pas le Enter key (13) plutôt que \n caractère ?

Ensuite, l'auteur a proposé deux façons de résoudre ces problèmes :

  1. utiliser fflush()

  2. écrire une fonction comme celle-ci :

    void
    clear (void)
    {    
      while ( getchar() != '\n' );
    }

Ce code a fonctionné. Mais je n'arrive pas à m'expliquer comment il fonctionne ? Parce que dans l'instruction while, nous utilisons getchar() != '\n' c'est-à-dire lire n'importe quel caractère à l'exception de '\n' ? si c'est le cas, le tampon d'entrée contient toujours le '\n' caractère ?

135voto

jamesdlin Points 13455

Le programme ne fonctionnera pas correctement parce qu'à la ligne 1, lorsque l'utilisateur appuie sur Entrée, il laissera dans le tampon d'entrée 2 caractères : Touche Entrée (code ASCII 13) et \n (code ASCII 10). Par conséquent, à la ligne 2, il lira le texte suivant \n et n'attendra pas que l'utilisateur entre un caractère.

Le comportement que vous observez à la ligne 2 est correct, mais ce n'est pas tout à fait la bonne explication. Avec les flux en mode texte, les fins de ligne utilisées par votre plateforme (retour chariot (0x0D) + saut de ligne (0x0A), CR nu ou LF nu) n'ont pas d'importance. La bibliothèque d'exécution C s'en chargera pour vous : votre programme verra seulement '\n' pour les nouvelles lignes.

Si vous tapez un caractère et appuyez sur la touche Entrée, ce caractère sera lu par la ligne 1, puis par la ligne 2. '\n' serait lu par la ligne 2. Voir J'utilise scanf %c pour lire une réponse Y/N, mais la saisie ultérieure est ignorée. de la FAQ comp.lang.c.

En ce qui concerne les solutions proposées, voir (toujours à partir de la FAQ de comp.lang.c) :

qui affirment en substance que la seule approche portable est de faire :

int c;
while ((c = getchar()) != '\n' && c != EOF) { }

Votre getchar() != '\n' fonctionne parce qu'une fois que vous appelez getchar() le caractère retourné a déjà été supprimé du flux d'entrée.

Par ailleurs, je me sens obligé de vous décourager d'utiliser scanf entièrement : Pourquoi tout le monde dit qu'il ne faut pas utiliser scanf ? Que dois-je utiliser à la place ?

54voto

Ramy Al Zuhouri Points 11065

Vous pouvez le faire (également) de cette manière :

fseek(stdin,0,SEEK_END);

21voto

Matt McNabb Points 14273

Une façon simple d'effacer la fin d'une ligne que vous avez déjà essayé de lire partiellement est de le faire :

int c;

while ( (c = getchar()) != '\n' && c != EOF ) { }

Il lit et rejette les caractères jusqu'à ce qu'il obtienne \n qui signale la fin du fichier. Il vérifie également la présence de EOF au cas où le flux d'entrée se fermerait avant la fin de la ligne. Le type de c doit être int (ou plus) afin de pouvoir conserver la valeur EOF .

Il n'y a pas de moyen portable de savoir s'il y a d'autres lignes après la ligne actuelle (si ce n'est pas le cas, alors getchar se bloquera pour la saisie).

14voto

Dmitri Points 4021

Les lignes :

int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
    ;

ne lit pas seulement les caractères avant le saut de ligne ( '\n' ). Il lit tous les caractères du flux (et les rejette) jusqu'à et y compris le prochain saut de ligne (ou EOF). Pour que le test soit vrai, il doit lire le saut de ligne en premier ; ainsi, lorsque la boucle s'arrête, le saut de ligne était le dernier caractère lu, mais il a été lu.

Quant à la raison pour laquelle il lit un saut de ligne au lieu d'un retour chariot, c'est parce que le système a traduit le retour en saut de ligne. Lorsque l'on appuie sur Entrée, cela signale la fin de la ligne... mais le flux contient un saut de ligne à la place, car c'est le marqueur normal de fin de ligne pour le système. Cela peut dépendre de la plate-forme.

De même, l'utilisation de fflush() sur un flux d'entrée ne fonctionne pas sur toutes les plates-formes ; par exemple, elle ne fonctionne généralement pas sous Linux.

10voto

Zack Points 44583

Mais je n'arrive pas à m'expliquer comment cela fonctionne ? Parce que dans l'instruction while, nous utilisons getchar() != '\n' c'est-à-dire lire n'importe quel caractère à l'exception de '\n' Si c'est le cas, le tampon d'entrée contient toujours le '\n' personnage ??? Est-ce que j'ai mal compris quelque chose ?

Ce que vous ne savez peut-être pas, c'est que la comparaison a lieu après getchar() supprime le caractère du tampon d'entrée. Ainsi, lorsque vous atteignez le '\n' il est consommé et puis vous sortez de la boucle.

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