scanf:" %[^ ] "pomija drugie wejście, ale" %[^ ] "nie. dlaczego?

Rozważ następujący kod:

#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;
}

Gdy zostanie wykonana tylko pierwsza scanf zatrzymuje się na znak zachęty. Program nie zatrzymuje się przez następne scanf s. ale jeśli łańcuch formatu zostanie zmieniony z "%[^\n]" na " %[^\n]" (zwróć uwagę na spację przed %), to działa dobrze. Czy jakiś istniejący znak nowej linii z poprzedniego bufora wejściowego jest automatycznie akceptowany ? Ale flushing stdin tego nie rozwiąże.

Jaka jest tego przyczyna?
 27
Author: Nan Xiao, 2011-05-21

6 answers

Po przeczytaniu tego, co chcesz, po prostu "skonsumuj" postać '\n'. Użyj następującej dyrektywy formatowej:

"%[^\n]%*c"

, które odczytuje wszystko aż do nowej linii do przekazywanego ciągu znaków, a następnie pochłonie pojedynczy znak (nową linię) bez przypisywania go do czegokolwiek (to '*' jest 'assignment suppression').

W Przeciwnym Razie,znak nowej linii pozostaje w strumieniu wejściowym i oczekuje natychmiastowego zakończenia kolejnych dyrektyw formatu "%[^\n]".

The problem z dodaniem znaku spacji do dyrektywy formatującej (" %[^\n]") polega na tym, że spacja będzie pasować do każdej białej spacji. Tak więc, będzie zjadać nowy wiersz od końca poprzedniego wejścia, ale będzie też zjadać wszelkie inne białe znaki(w tym wiele nowych linii).

Zaktualizuj swój przykład:

  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");
 39
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-21 20:23:49

Kiedy używasz scanf() do odczytu łańcuchów, Twój format string (%[^\n]) mówi funkcji, aby odczytała każdy znak, który nie jest '\n'. Pozostawia znak '\n' w buforze wejściowym. Więc kiedy próbujesz przeczytać str2 i str3, scanf() znajduje pierwszą rzeczą w buforze jest '\n' za każdym razem i, ze względu na łańcuch formatu, nie usuwa go z bufora wejściowego. To, czego potrzebujesz, to getchar() pomiędzy czasami odczytu z bufora wejściowego(często umieszczane bezpośrednio po scanf()). Od istnieje już '\n' w buforze, Twój program nie będzie się zawieszał, ponieważ nie będzie musiał czekać na wejście dla getchar(), aby otrzymać. Spróbuj. :)

Dla tych, którzy nie mają pojęcia, co robi ten modyfikator scanf(), oto odpowiedni fragment http://linux.die.net/man/3/scanf -

[

Dopasowuje niepustą sekwencję znaki z podanego zbioru akceptowane znaki; następny wskaźnik musi być wskaźnik do znaku, a tam musi być wystarczająco dużo miejsca dla wszystkich znaki w łańcuchu, plus a kończący bajt null. Zwykły skip wiodąca biała przestrzeń jest tłumiona. Sznurek ma się składać z znaki w (lub nie w) konkretnym set; zbiór jest zdefiniowany przez znaki między nawiasami otwartymi [ charakter i ścisły nawias ] charakter. Zestaw nie obejmuje tych znaków, jeśli pierwszy znak po otwartym wsporniku jest circumflex (^). W celu włączenia nawiasu zamkniętego w set, make it the pierwszy znak po wspornik otwarty lub obwód; każda inna pozycja zakończy zestaw. Znak myślnika-jest również specjalne; gdy umieszczone są pomiędzy dwoma innymi znaków, dodaje wszystkie interwencje postacie do kompletu. Aby dołączyć myślnik, niech będzie ostatnim znakiem przed ostatnim zamknięciem. Na instancja, [^] 0-9 -] oznacza zbiór "wszystko poza ścisłym nawiasem, zero przez dziewięć i myślnik". The string kończy się pojawieniem się postać nie w (lub z circumflex, in) ustawione lub gdy pole / align = "left" /

 6
Author: Chrono Kitsune,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-21 16:56:14

Także: Aby przeczytać ciąg znaków:

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

/ / to znaczy czytać aż spotkasz '\n' , potem trash że '\n '

:)

 2
Author: MLSC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-05 20:27:39

Wystarczy użyć getchar() po funkcji scanf ().

 1
Author: Abdus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-04 13:35:37

Tylko dodaję nieco dalej do powyższej odpowiedzi- Jeśli chcemy usunąć jakiś konkretny wzorzec, Załóżmy liczby 0-9, ze strumienia wejściowego, wtedy będziemy musieli użyć getchar () do flushing buffer.

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);

Więc tutaj, jeśli przekażesz ashish019, to tylko ashish zostanie skopiowany do str, a 019 zostanie w buforze, więc do wyczyszczenia potrzebujesz getchar () wiele razy.

 0
Author: Ashish Maurya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-13 16:53:26

Użyj fflush(stdin), aby wyczyścić bufor wejściowy po odczytaniu każdego wejścia.

 -3
Author: Murtaza Amravatiwala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-15 12:18:11