Bardzo często na forum pojawia się pytanie: jak zabezpieczyć program przed wpisaniem liter, gdy program oczekuje na liczby.
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
  }
 

Kategoria: C » FAQ

7 komentarzy

Avatar: adf88
Napisany 2012-04-26 11:43 przez adf88

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ść.

Avatar: Shalom
Napisany 2011-04-12 01:13 przez Shalom

@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ć.

Avatar: Azrael_Valedhel
Napisany 2011-04-11 22:31 przez Azrael_Valedhel

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.

Avatar: Janek566
Napisany 2011-03-07 15:53 przez Janek566

mogłbyś dodać kod w delphi :P

Brak avatara
Napisany 2010-08-23 21:10 przez Olivia

Hm. A niedawno czytałam, że to błąd. Dzięki za wyprostowanie.

Avatar: Shalom
Napisany 2010-08-23 21:08 przez Shalom

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

Brak avatara
Napisany 2010-08-23 20:07 przez Olivia

Rozwiązanie c chyba nie jest zbyt dobre.  char nie przechowa EOF.

4programmers.net