web-dev-qa-db-fra.com

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 car, sur la ligne 1, lorsque l’utilisateur appuie sur la touche Entrée, il laisse dans le tampon de saisie 2 le caractère: Enter key (ASCII code 13) et \n (ASCII code 10). Par conséquent, à la ligne 2, il lira le \n et n'attendra pas que l'utilisateur entre un caractère.

OK, j'ai ça. Mais ma première question est: Pourquoi la seconde getchar() (ch2 = getchar();) ne lit pas le Enter key (13), plutôt que le \n?

Ensuite, l’auteur a proposé deux moyens de résoudre ces problèmes:

  1. utiliser fflush()

  2. écrivez une fonction comme celle-ci:

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

Ce code a fonctionné réellement. Mais je ne peux pas m'expliquer comment ça marche? Parce que dans l'instruction while, nous utilisons getchar() != '\n', cela signifie lire n'importe quel caractère, à l'exception de '\n'? si tel est le cas, il reste encore dans le tampon d'entrée le caractère '\n'?

68
ipkiss

Le programme ne fonctionnera pas correctement car sur la ligne 1, lorsque l'utilisateur appuiera sur la touche 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\n et n'attendra pas que l'utilisateur entre un caractère.

Le comportement que vous voyez à la ligne 2 est correct, mais l'explication n'est pas tout à fait correcte. Avec les flux en mode texte, les fins de ligne utilisées par votre plate-forme importent peu (que ce soit un retour chariot (0x0D) + un saut de ligne (0x0A), un CR nu ou un LF nu). La bibliothèque d’exécution C s’occupe de cela pour vous: votre programme ne verra que '\n' pour les nouvelles lignes.

Si vous avez tapé un caractère et appuyé sur Entrée, le caractère saisi sera lu par la ligne 1, puis '\n' sera lu par la ligne 2. Voir J'utilise scanf %c pour lire une réponse O/N, mais les entrées ultérieures sont ignorées. de la FAQ comp.lang.c.

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

qui stipulent fondamentalement que la seule approche portable consiste à faire:

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

Votre boucle getchar() != '\n' fonctionne car une fois que vous avez appelé getchar(), le caractère renvoyé a déjà été supprimé du flux d'entrée.

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

75
jamesdlin

Vous pouvez le faire (aussi) de cette façon:

fseek(stdin,0,SEEK_END);
37
Ramy Al Zuhouri

Les lignes:

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

ne lit pas uniquement les caractères précédant le saut de ligne ('\n'). Il lit tous les caractères du flux (et les supprime) jusqu'à et y compris le prochain saut de ligne (ou EOF est rencontré). Pour que le test soit vrai, il faut d'abord lire le saut de ligne; ainsi, lorsque la boucle s'arrête, le saut de ligne était le dernier caractère lu, mais il a été lu.

Quant à savoir pourquoi il lit un saut de ligne au lieu d’un retour à la ligne, c’est que le système a traduit le retour en saut de ligne. Lorsque vous appuyez sur la touche Entrée, la fin de la ligne est signalée ... mais le flux contient un saut de ligne, car il s'agit du marqueur de fin de ligne normal du système. Cela pourrait dépendre de la plate-forme.

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

11
Dmitri

Un moyen portable pour effacer jusqu'à la fin d'une ligne que vous avez déjà essayé de lire partiellement est:

int c;

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

Ceci lit et supprime les caractères jusqu'à obtenir \n qui signale la fin du fichier. Il vérifie également la valeur EOF au cas où le flux d'entrée serait fermé avant la fin de la ligne. Le type de c doit être int (ou supérieur) pour pouvoir conserver la valeur EOF.

Il n'y a pas de moyen portable de savoir s'il y a plus de lignes après la ligne actuelle (s'il n'y en a pas, alors getchar bloquera l'entrée).

10
M.M

Mais je ne peux pas m'expliquer comment ça marche? Parce que dans l'instruction while, nous utilisons getchar() != '\n', cela signifie lire n'importe quel caractère sauf '\n' ?? si tel est le cas, il reste encore dans le tampon d'entrée le caractère '\n' ??? Est-ce que je comprends mal quelque chose?

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

8
zwol

tu peux essayer

scanf("%c%*c", &ch1);

où% * c accepte et ignore la nouvelle ligne

une autre méthode au lieu de fflush (stdin) qui invoque un comportement indéfini que vous pouvez écrire

while((getchar())!='\n');

n'oubliez pas le point-virgule après la boucle while

6
kapil

Une autre solution non encore mentionnée consiste à utiliser: rewind (stdin);

3
James Blue
unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

-ou-

utiliser peut-être utiliser _getch_nolock() .. ???

1
Michael Grieswald

Je rencontre un problème en essayant d'implémenter la solution

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

Je publie un petit ajustement 'Code B' pour tous ceux qui ont peut-être le même problème.

Le problème était que le programme m'a gardé attraper le caractère '\ n', indépendamment du caractère d'entrée, voici le code qui m'a donné le problème.

Code A

int y;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   continue;
}
printf("\n%c\n", toupper(y));

et l'ajustement consistait à "attraper" le caractère (n-1) juste avant l'évaluation de la condition dans la boucle Tant, voici le code:

Code B

int y, x;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   x = y;
}
printf("\n%c\n", toupper(x));

L'explication possible est que, pour que la boucle while se rompt, elle doit affecter la valeur '\ n' à la variable y, donc ce sera la dernière valeur affectée.

Si j'ai oublié quelque chose avec l'explication, code A ou code B, dites-moi s'il vous plaît, je suis à peine nouveau en c.

j'espère que ça aide quelqu'un

1
antadlp

Court, portable et déclaré dans stdio.h

stdin = freopen(NULL,"r",stdin);

Ne se bloque pas dans une boucle infinie quand il n'y a rien sur stdin à vider comme la ligne bien connue suivante:

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

Un peu cher, ne l'utilisez pas dans un programme qui doit effacer le tampon à plusieurs reprises.

Volé d'un collègue :)

0
Jason Enochs