scanf () laisse le nouveau caractère de ligne dans le tampon

87

J'ai le programme suivant:

int main(int argc, char *argv[])
{
  int a, b;
  char c1, c2;
  printf("Enter something: ");
  scanf("%d",&a); // line 1
  printf("Enter other something: ");
  scanf("%d", &b); // line 2

  printf("Enter a char: ");
  scanf("%c",&c1); // line 3
  printf("Enter another char: ");
  scanf("%c", &c2); // line 4

  printf("Done"); // line 5

  system("PAUSE");

  return 0;
}

Comme je l'ai lu dans le livre C, l'auteur dit qu'il a scanf()laissé un nouveau caractère de ligne dans la mémoire tampon, par conséquent, le programme ne s'arrête pas à la ligne 4 pour que l'utilisateur entre les données, il stocke plutôt le caractère de nouvelle ligne dans c2 et passe à ligne 5.

Est-ce correct?

Cependant, cela ne se produit-il qu'avec charles types de données? Parce que je n'ai pas vu ce problème avec intles types de données comme dans les lignes 1, 2, 3. Est-ce vrai?

ipkiss
la source
Il est parfois suggéré que fflush(stdin)peut être utilisé avant l'appel à scanf()pour un seul caractère. Veuillez lire Utilisationfflush(stdin) pour une discussion des avantages et des inconvénients et des alternatives à cette méthode (qui fonctionne plus ou moins sous Windows et ne fonctionne pas dans la plupart des autres endroits).
Jonathan Leffler
Pourriez-vous s'il vous plaît nous dire à quel livre vous faites référence.?
surya kiran

Réponses:

78

La scanf()fonction ignore automatiquement les espaces blancs avant d'essayer d'analyser les conversions autres que les caractères. Les formats de caractères (principalement %c; également les jeux de balayage %[…]- et %n) sont l'exception; ils ne sautent pas d'espaces.

À utiliser " %c"avec un blanc de début pour ignorer les espaces blancs facultatifs. N'utilisez pas de blanc de fin dans une scanf()chaîne de format.

Notez que cela ne consomme toujours aucun espace blanc de fin laissé dans le flux d'entrée, même pas jusqu'à la fin d'une ligne, alors méfiez-vous de cela si vous utilisez également getchar()ou fgets()sur le même flux d'entrée. Nous sommes juste en train de faire en sorte que scanf ignore les espaces avant les conversions, comme il le fait pour %det d'autres conversions sans caractère.


Notez que les "directives" sans espace (pour utiliser la terminologie scanf POSIX ) autres que les conversions, comme le texte littéral dans scanf("order = %d", &order);ne saute pas non plus les espaces. Le littéral orderdoit correspondre au caractère suivant à lire.

Donc, vous voulez probablement " order = %d"y aller si vous voulez sauter une nouvelle ligne de la ligne précédente mais avez toujours besoin d'une correspondance littérale sur une chaîne fixe, comme cette question .

Jérémie Willcock
la source
7
%c, %n, %[]Sont les 3 attentes spécifiques qui ne consomment pas de premier plan des espaces blancs.
chux - Réintégrer Monica
@chux Donc, dans d'autres cas, le scanf efface tous les espaces avant dans le tampon ou les ignore pour qu'ils entrent mais ils sont toujours là?
Suraj Jain
@SurajJain Oui,
chux - Réintégrer Monica le
3
Voir Fin de blanc dans la scanf()chaîne de format et scanf()demander deux fois l'entrée alors que je m'attends à ce qu'il ne demande qu'une seule fois pour une discussion sur les blancs de fin dans les chaînes de format. C'est une mauvaise idée - incroyablement mauvaise si vous vous attendez à une interaction humaine et mauvaise pour l'interaction avec le programme.
Jonathan Leffler
31

Utilisez scanf(" %c", &c2);. Cela résoudra votre problème.

Shweta
la source
7

Une autre option (que j'ai obtenue à partir d' ici ) est de lire et de supprimer la nouvelle ligne en utilisant l' option de suppression d'affectation . Pour ce faire, il suffit de mettre un format pour lire un caractère avec un astérisque entre %et c:

scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3

scanf lira alors le caractère suivant (c'est-à-dire la nouvelle ligne) mais ne l'attribuera à aucun pointeur.

En fin de compte, cependant, je soutiendrais la dernière option de la FAQ :

Ou, selon vos besoins, vous pouvez également oublier scanf () / getchar (), utiliser fgets () pour obtenir une ligne de texte de l'utilisateur et l'analyser vous-même.

brandizzi
la source
2
Le problème avec cette technique est que si l'utilisateur tape aalors espace puis nouvelle ligne, la conversion de caractères supprimée lit l'espace et laisse toujours la nouvelle ligne. Si l'utilisateur tape supercalifragilisticexpialidociousquand vous le souhaitez a, vous avez beaucoup de caractères supplémentaires à gérer. Vous ne pouvez jamais dire non plus si une conversion supprimée de fin réussit - elles ne sont pas comptées dans le retour de scanf().
Jonathan Leffler le
3

À utiliser getchar()avant d'appeler en second scanf().

scanf("%c", &c1);
getchar();  // <== remove newline
scanf("%c", &c2);
Jiwon
la source
1
Cela fonctionne à condition que l'utilisateur n'ait rien tapé d'autre - des blancs de fin, par exemple. Mais ce n'est pas aussi bon qu'une boucle qui scanne la prochaine nouvelle ligne: int c; while ((c = getchar()) != EOF && c != '\n') ;(écrite sur trois lignes quand elle n'est pas dans un commentaire). C'est souvent suffisant; ce n'est pas infaillible (et vous devez vous rappeler que les imbéciles sont très intelligents pour écraser les choses).
Jonathan Leffler