Zabezpieczenie przed wpisywaniem liter
Najprostsze rozwiązanie w języku C++ wygląda tak:
int zmienna; while(!(cin>>zmienna)) //dopóki strumień jest w stanie błędu -> dopóki podawane są błędne dane { //ew komunikat błędu cin.clear(); //kasowanie flagi błędu strumienia cin.sync(); //kasowanie zbędnych znaków z bufora } //tutaj na pewno wczytano poprawne dane do zmienna
W języku C nie istnieje równie proste rozwiązanie tego problemu. Można spróbować użyć:
int zmienna; while(scanf("%d", &zmienna) != 1) //dopóki nie uda się wczytać { //ew. komunikat błędu fflush(stdin); }
Ale nie jest to dobre rozwiązanie, ponieważ jest zależne od implementacji. fflush() nie zawsze powoduje wyczyszczenie bufora!
Rozwiązanie działające w każdej sytuacji (i implementacji) polega na żmudnym wyciągnięciu z stdin zalegających tam, zbędnych znaków (dodatkowa pętla w miejscu fflush())
int zmienna; while(scanf("%d", &zmienna) != 1) //dopóki nie uda się wczytać { //ew. komunikat błędu while(char c=getchar() != '\n' && c!=EOF); //pętla wyciągająca znaki z bufora }
7 komentarzy
@Azrael_Valedhel nie do końca się zgodzę. Dokumentacja twierdzi:
"This effectively means that the unread characters in the buffer are discarded"
Ba, nawet jako przykład użycia pokazane jest jak czyścić strumień cin.
A co do działania fflush to jest wyraźnie napisane że nie należy go używać.
Oj do poprawy ten wpis, `istream::sync()` różnie działa zależnie od implementacji i od tego na jakim strumieniu jest wywołane, a `fflush(stdin)` to niezdefiniowane zachowanie.
Hm. A niedawno czytałam, że to błąd. Dzięki za wyprostowanie.
"In the C Standard Library, character read functions such as getchar return a value equal to the symbolic value (macro) EOF to indicate that an end-of-file condition has occurred"
Parafrazując: EOF w powyższym kodzie to nie jest wartość zmiennej char, a pewne makro, które ma "specjalną wartość". Funkcja getchar() sprytnie nie zwraca nam "znaku eof" (bo takowego w ascii nie ma) a jedynie ową "specjalną wartość" kiedy natrafi na prawdziwego eof'a. Stąd też kod jest poprawny ;)
Rozwiązanie c chyba nie jest zbyt dobre. char nie przechowa EOF.
Zmienna 'c' powinna być typu 'int'. W przeciwnym razie, jeśli 'char' jest domyślnie 'signed', znak 0xFF będzie rozpoznany jako 'EOF' (-1), bo '(signed char)0xFF == EOF'. Jeśli 'char' jest domyślnie 'unsigned' to jeszcze gorzej, 'EOF' będzie puszczone jako zwykły znak, bo '(unsigned char)EOF != EOF'.
Właśnie dlatego 'getchar' zwraca 'int' a nie 'char', aby można było rozróżnić znak (0-255) od EOF (-1). W zasadzie standard nie precyzuje ile wynosi 'EOF', nie koniecznie -1. W każdym bądź razie ile by to nie były to rzutowane na 'char' wygeneruje jeden z kodów ASCII. Standard gwarantuje, że można porównać wynik 'getchar' do EOF. Jeśli ten wynik rzutujemy na 'char' to tracimy precyzję i porównanie nie musi się powieść.