scanf () pozostawia znak nowej linii w buforze


93

Mam następujący program:

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 chartypów danych? Ponieważ nie widziałem tego problemu z inttypami danych jak w liniach 1, 2, 3. Czy to prawda?


Czasami sugeruje się, że fflush(stdin)można go użyć przed wywołaniem scanf()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).
Jonathan Leffler

Czy możesz nam powiedzieć, do której książki się odnosisz.?
surya kiran

Odpowiedzi:


82

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ągu scanf()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()lub fgets()w tym samym strumieniu wejściowym. Po prostu otrzymujemy scanf, aby pomijać białe znaki przed konwersją, tak jak w %dprzypadku 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ł ordermusi 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 .


9
%c, %n, %[]Są 3 ściśle określonych oczekiwań, które nie spożywają wiodącą spacje.
chux - Przywróć Monikę

@chux Czy w innych przypadkach scanf czyści wszystkie białe spacje w buforze lub ignoruje je przy wprowadzaniu, ale nadal tam są?
Suraj Jain

@SurajJain Tak,
chux - Przywróć Monikę

3
Zobacz końcowe puste miejsce w scanf()ciągu formatu i scanf()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.
Jonathan Leffler


8

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 %a c:

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 :

Lub, w zależności od twoich wymagań, możesz również zapomnieć o scanf () / getchar (), użyć fgets (), aby pobrać linię tekstu od użytkownika i przeanalizować ją samodzielnie.


3
Problem z tą techniką polega na tym, że jeśli użytkownik wpisze, aa 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, supercalifragilisticexpialidociouskiedy się spodziewasz a, 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 z scanf().
Jonathan Leffler

4

Użyj getchar()przed wezwaniem drugiego scanf().


1
Działa to pod warunkiem, że użytkownik nie wpisał nic innego - na przykład końcowe spacje. Ale nie jest tak dobra jak pętla, która skanuje do następnej nowej linii: 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).
Jonathan Leffler
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.