web-dev-qa-db-fra.com

scanf: "% [^ \ n]" ignore la 2e entrée mais pas "% [^ \ n]". Pourquoi?

Considérez le code suivant:

#include <stdio.h>

int main (void)
{
  char str1[128], str2[128], str3[128];

  printf ("\nEnter str1: ");
  scanf ("%[^\n]", str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf ("%[^\n]", str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf ("%[^\n]", str3);
  printf ("\nstr3 = %s", str3);

  printf ("\n");
  return 0;
}

Lorsqu'il est exécuté, seul le premier scanf s'arrête pour l'invite. Le programme ne s'arrête pas pour les scanf s suivants. Mais si la chaîne de format est modifiée de "%[^\n]" à " %[^\n]" (notez l'espace vide avant %), alors ça marche. Est-ce que certains caractères de nouvelle ligne existants du tampon d'entrée précédent sont automatiquement acceptés? Mais le rinçage stdin ne résout pas ce problème.

Quelle est la cause de cela.

28
phoxis

Vous avez juste besoin de "consommer" le '\n' caractère après avoir lu ce que vous voulez. Utilisez la directive de format suivante:

"%[^\n]%*c"

Qui lira tout jusqu'à la nouvelle ligne dans la chaîne que vous passez, puis consommera un seul caractère (la nouvelle ligne) sans l'attribuer à rien (que '*' est la 'suppression d'affectation').

Sinon, la nouvelle ligne est laissée dans le flux d'entrée en attendant de terminer immédiatement le "%[^\n]" directives de format.

Le problème avec l'ajout d'un caractère espace à la directive format (" %[^\n]") est que l'espace correspondra à tout espace blanc. Ainsi, il mange la nouvelle ligne à la fin de l'entrée précédente, mais il mange également tous les autres espaces (y compris les nouvelles lignes).

Mettez à jour votre exemple:

  char* fmt = "%[^\n]%*c";

  printf ("\nEnter str1: ");
  scanf (fmt, str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf (fmt, str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf (fmt, str3);
  printf ("\nstr2 = %s", str3);

  printf ("\n");
43
Michael Burr

Lorsque vous utilisez scanf() pour lire les chaînes, votre chaîne de formatage (%[^\n]) Indique à la fonction de lire chaque caractère qui n'est pas '\n'. Cela laisse le caractère '\n' Dans le tampon d'entrée. Ainsi, lorsque vous essayez de lire str2 Et str3, scanf() trouve la première chose dans le tampon est '\n' À chaque fois et, en raison de la chaîne de format , ne le supprime pas du tampon d'entrée. Ce dont vous avez besoin est une getchar() entre les heures que vous lisez à partir du tampon d'entrée (souvent placée immédiatement après scanf()). Puisqu'il y a déjà un '\n' Dans le tampon, votre programme ne semblera pas se bloquer car il n'aura pas à attendre la saisie de getchar() pour recevoir. Essayez-le. :)

Pour ceux qui n'ont aucune idée de ce que fait ce modificateur scanf(), voici un extrait pertinent de http://linux.die.net/man/3/scanf -

[

Correspond à une séquence de caractères non vide de l'ensemble spécifié de caractères acceptés; le pointeur suivant doit être un pointeur sur char, et il doit y avoir suffisamment de place pour tous les caractères de la chaîne, plus un octet nul final. Le saut habituel de l'espace blanc de tête est supprimé. La chaîne doit être composée de caractères dans (ou pas dans) un ensemble particulier; l'ensemble est défini par les caractères entre le caractère crochet ouvert [caractère et un crochet proche]. L'ensemble exclut ces caractères si le premier caractère après le crochet ouvert est un circonflexe (^). Pour inclure une parenthèse fermée dans l'ensemble, faites-en le premier caractère après la parenthèse ouverte ou le circonflexe; toute autre position mettra fin à l'ensemble. Le trait d'union - est également spécial; lorsqu'il est placé entre deux autres personnages, il ajoute tous les personnages intermédiaires à l'ensemble. Pour inclure un trait d'union, faites-en le dernier caractère avant la dernière parenthèse de fermeture. Par exemple, [^] 0-9-] signifie l'ensemble "tout sauf les parenthèses fermées, zéro à neuf et le tiret". La chaîne se termine par l'apparition d'un caractère qui n'est pas dans l'ensemble (ou, avec un accent circonflexe, dans) ou lorsque la largeur du champ est épuisée.

7
user539810

AUSSI: Pour lire une chaîne:

scanf("%[^\n]\n", a);

// cela signifie lire jusqu'à ce que vous rencontriez '\ n', puis supprimez ce '\ n'

:)

3
MLSC

Utilisez simplement un getchar () après la fonction scanf ().

1
Abdus

Ajoutant juste un peu plus à la réponse ci-dessus - Si nous voulons supprimer un modèle spécifique, supposons les nombres 0-9, du flux d'entrée, alors nous devrons utiliser getchar () pour vider le tampon.

scanf("%[^0-9\n]", str1);
while(getchar() != '\n'); // this approach is much better bcz it will
                         // remove any number of left characters in buffer.
scanf("%c", &ch);

Donc, ici, si vous passez ashish019, seul ashish sera copié dans str et 019 sera laissé dans le tampon, donc pour effacer, vous aurez besoin de getchar () plusieurs fois.

0
Ashish Maurya