Mam następujący program:
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;
}
Jak czytałem w książce C, autor mówi, że scanf()
zostawił znak nowej linii w buforze, dlatego program nie zatrzymuje się na linii 4, aby użytkownik wprowadził dane, a raczej przechowuje znak nowej linii w c2 i przechodzi do wiersz 5.
Czy to prawda?
Jednak czy dzieje się tak tylko w przypadku char
typów danych? Ponieważ nie widziałem tego problemu z int
typami danych jak w liniach 1, 2, 3. Czy to prawda?
fflush(stdin)
można go użyć przed wywołaniemscanf()
pojedynczego znaku. Przeczytaj Korzystaniefflush(stdin)
z omówienia zalet i wad oraz alternatyw dla tej metody (która działa mniej więcej w systemie Windows i nie działa w większości innych miejsc).Odpowiedzi:
W
scanf()
przeskakuje funkcyjne wiodące spacje przed automatycznie próbuje analizować konwersje inne niż litery. Wyjątek stanowią formaty znaków (głównie%c
; także zestawy skanowania%[…]
- i%n
); nie pomijają białych znaków.Użyj
" %c"
ze spacją wiodącą, aby pominąć opcjonalne białe znaki. Nie używaj końcowego spacji w ciąguscanf()
formatu.Zauważ, że to nadal nie zużywa żadnych końcowych spacji pozostawionych w strumieniu wejściowym, nawet do końca linii, więc uważaj na to, jeśli używasz również
getchar()
lubfgets()
w tym samym strumieniu wejściowym. Po prostu otrzymujemy scanf, aby pomijać białe znaki przed konwersją, tak jak w%d
przypadku konwersji innych niż znaki.Zauważ, że "dyrektywy" niebędące białymi znakami (aby używać terminologii POSIX scanf ) inne niż konwersje, takie jak tekst literału w,
scanf("order = %d", &order);
również nie pomijają białych znaków. Literałorder
musi pasować do następnego znaku do odczytania.Więc prawdopodobnie chcesz
" order = %d"
tam, jeśli chcesz pominąć nową linię z poprzedniej linii, ale nadal potrzebujesz dosłownego dopasowania do ustalonego ciągu, jak to pytanie .źródło
%c
,%n
,%[]
Są 3 ściśle określonych oczekiwań, które nie spożywają wiodącą spacje.scanf()
ciągu formatu iscanf()
dwa razy prosząc o dane wejściowe, podczas gdy oczekuję, że poprosi tylko raz o omówienie końcowych spacji w ciągach formatu. To zły pomysł - zdumiewająco zły, jeśli spodziewasz się interakcji między ludźmi i zły dla interakcji programu.Użyj
scanf(" %c", &c2);
. To rozwiąże twój problem.źródło
Inną opcją (którą dostałem stąd ) jest odczytanie i odrzucenie nowej linii za pomocą opcji tłumienia przypisania . Aby to zrobić, po prostu umieściliśmy format do odczytu znaku z gwiazdką między
%
ac
:scanf("%d%*c",&a); // line 1 scanf("%c%*c",&c1); // line 3
scanf
odczyta wtedy następny znak (czyli nową linię), ale nie przypisze go do żadnego wskaźnika.Ostatecznie jednak chciałbym powtórzyć ostatnią opcję FAQ :
źródło
a
a następnie spacja, a następnie znak nowej linii, powstrzymana konwersja znaków odczytuje spację i nadal pozostawia znak nowej linii. Jeśli użytkownik wpisze,supercalifragilisticexpialidocious
kiedy się spodziewasza
, masz do czynienia z wieloma dodatkowymi postaciami. Nigdy też nie można stwierdzić, czy końcowa, stłumiona konwersja zakończyła się powodzeniem - nie są one uwzględniane w powrocie zscanf()
.Użyj
getchar()
przed wezwaniem drugiegoscanf()
.scanf("%c", &c1); getchar(); // <== remove newline scanf("%c", &c2);
źródło
int c; while ((c = getchar()) != EOF && c != '\n') ;
(zapisana w trzech wierszach, jeśli nie jest w komentarzu). Często jest wystarczające; nie jest niezawodny (i musisz pamiętać, że głupcy są bardzo sprytni w rozwalaniu rzeczy).