2013-07-24 18 views
5

Próbuję: - Aby ponownie odczytać wartość, jeśli użytkownik wprowadzi niepoprawną wartość. Ale problem polega na tym, że scanf() wykonuje się tylko jeden raz i nie wykona żadnego innego czasu, a programy utkną w nieskończonej pętli.Scanf nie uruchomi się po raz drugi

#include<stdio.h> 
#include<math.h> 
main() 
{ 
    unsigned int a; 
    unsigned int b = pow(2,M-1); 
    unsigned int c; 
    int x; 

    printf("b = %i",b); 

    input: 
    fflush(stdin); 
    fflush(stdout); 
    printf("\nEnter any integer: "); 
    x = scanf("%u",&a); 

    printf("%u",a); 
    if(x==0) 
     goto input; 

    printf("\na = %i",a); 

    c = a & b; 

    printf("\nc = %i",c); 

    if(c) 
     printf("\nthe bit %i is set",M); 
    else 
     printf("\nthe bit %i is not set",M); 
} 

Próbowałem za pomocą dodawania przestrzeń przed %u a także próbowali fflush(stdin) ale nic nie działało.

EDYCJA: Wiem, że użycie goto nie jest zalecane, ale muszę to zrobić w ten sposób. (Używanie pętli nie jest opcją). M to makro zdefiniowane za pomocą wiersza polecenia gcc w czasie kompilacji.

+0

możesz użyć pętli do while w tym przypadku. Proszę zobaczyć zmodyfikowany kod podany poniżej: – stev

Odpowiedz

9

Ostrzeżenie: fflush(stdin); może być niezdefiniowanym zachowaniem. Czytaj: Why fflush(stdin) is wrong?

int fflush(FILE *ostream);
W ostream punkty do strumienia wyjściowego lub strumienia aktualizacji, w której ostatniej operacji nie było wejście, funkcja fflush powoduje żadnych dane niepisane dla tego strumienia mają być dostarczone do środowiska hosta do zapisania w pliku; w przeciwnym razie behavior jest Undefined.

Można spróbować pętlę i czytać aż EOF lub \n podane this FAQ entry zamiast fflush(stdin) jak sugerowali poniżej na moją odpowiedź.

Edit: dzięki @Jonathan Leffler:

Istnieją platformy gdzie fflush(stdin) jest w pełni zdefiniowane (jak niestandardowym rozszerzeniem na tej platformie). Podstawowym przykładem jest dobrze znana rodzina systemów znanych jako system Windows. Specyfikacja Microsoft: int fflush(FILE *stream);Jeśli stream jest otwarty do wprowadzania, fflush czyści zawartość bufora.

Mam dodatkowe wątpliwości w kodzie; co to jest M w wyrażeniu unsigned int b = pow(2,M-1);? Powinien to być błąd, jeśli go nie zdefiniujesz. Czy publikujesz kompletny kod?

chodzi Ci logikę wykrywania błędów:

ponownie odczytać wartość, jeśli użytkownik wpisze nieprawidłowy

Nie, scanf() nie zwraca kod błędu. Zwraca liczbę udanych konwersji.

int scanf (const char * format, ...);
Return Value
W przypadku powodzenia funkcja zwraca liczbę elementów listy argumentów skutecznie wypełnione.Liczba ta może być równa , gdy oczekiwana liczba elementów lub będzie mniejsza (nawet zero) ze względu na błąd dopasowania, błąd odczytu lub zasięg końca pliku.

Jeśli błąd odczytu dzieje lub plik end-of-gdy nadejdzie czytanie, właściwy wskaźnik jest ustawiony (feof lub ferror). A jeśli wydarzy się albo zanim jakiekolwiek dane zostaną odczytane pomyślnie, zwracana jest EOF.

Jeżeli błąd kodowania dzieje interpretacji szerokie znaki, funkcja ustawia errno do EILSEQ.

Tak naprawdę w zależności od napotkanego błędu wartość zwracana może wynosić zero, EOF. Powinieneś użyć makra int ferror (FILE * stream); i errno do wykrywania błędów (sprawdź przykład podany przy łączu).

Błędy możliwe z powodu nieprawidłowej wejścia może być:

EILSEQ: sekwencja bajt wejściowy nie tworzy ważny znak.
EINVAL: Za mało argumentów; lub format ma wartość NULL.
ERANGE: Konwersja liczby całkowitej przekroczyłaby rozmiar, który można zapisać w odpowiednim typie całkowitym.

Aby uzyskać pełną listę, sprawdź: scanf manual.

Powód nieskończonej pętli:

System śledzi które wejście zostało widziałem do tej pory. Każde połączenie z numerem scanf rozpoczyna się od ostatniego zatrzymania pasującego wejścia. Oznacza to, że jeśli wystąpił błąd z poprzednią wersją scanf, dane wejściowe, których nie udało się dopasować, pozostały nieprzeczytane, tak jak użytkownik wpisany z wyprzedzeniem. Jeśli nie zostanie podjęta ostrożność, aby odrzucić błąd, a do odczytu wejścia używana jest pętla, twój program może zostać złapany w nieskończoną pętlę.

Tak na przykład w kodzie:

x = scanf("%u", &a); 
     // ^
     // need a number to be input 

Ale załóżmy, że nie trzeba wpisywać numer, ale nieprawidłowy ciąg jest wpisany na przykład "name" (zamiast liczby, jak mówisz). Spowoduje to niepowodzenie funkcji scanf() przy próbie dopasowania liczby całkowitej bez znaku ("%u"), a słowo "name" pozostanie nieprzeczytane. Tak więc, następnym razem, gdy pętla zostanie przeprowadzona, scanf() nie czeka na nowe dane wprowadzone przez użytkownika, próbuje ponownie przekonwertować "nazwę".

Podobnie jeśli wejście było 29.67, w "%u" będzie pasował do dwóch pierwszych tylko znaki (The 29), pozostawiając .67 jako nieprzeczytane wejście do następnego wywołania scanf().

Nawet jeśli dane wejściowe są poprawne, jako 29, znak nowej linii, który zakończył wprowadzanie danych, pozostaje nieprzeczytany.Zwykle nie stanowi to problemu, ponieważ większość konwersji automatycznie pomija wiodącą białą przestrzeń, na przykład końcowy znak nowej linii z poprzedniego wiersza. Jednak niektóre konwersje ("%c" i "%[") nie pomijają żadnej wiodącej białej przestrzeni, więc musisz to zrobić ręcznie.

Aby uniknąć tego nieskończonej pętli Jedna sugestia:

(pamiętaj: jak zaleca się stosowanie ferror(), błąd wartości korzystne jest, aby wykryć nieprawidłowe dane Dodatkowo, to właśnie za cel nauki i jeśli was. należy wdrożyć poważne aplikacji należy użyć fgets(str) zamiast scanf() następnie analizować str że wejście do sprawdzenia, czy wkład jest ważny)

input: 
    //fflush(stdout); //use if needed, as \n used in printf no need of fflush-stdout 
    printf("\nEnter any integer: "); 
    x = scanf("%u", &a); // always wait for new symbols 
    printf("%u", a); 

    if(x == 0){ // x=0, if error occurred 
     // read all unread chars 
     while ((ch = getchar()) != '\n' && ch != EOF); 
     goto input; 
    } 

to tylko sugestia, że ​​będzie p prawdopodobnie działaj z twoim kodem (pracował dla mnie, twój kod + gcc). Ale jeśli używasz tej techniki nieprawidłowo może pozostawić błąd w kodzie:

Czytaj How do I flush the input buffer?

Jeżeli jesteś pewien, że niechciane dane w strumieniu wejściowym, można użyć niektóre z następującego kodu snippets do ich usunięcia. Jeśli jednak zadzwonisz do nich, gdy nie ma danych w strumieniu wejściowym, program będzie czekał, aż pojawi się, co daje niepożądane wyniki.

+1

+1 - * Możesz wypróbować pętlę i przeczytać do EOF lub \ n *, wyraźnie zaznacza, że ​​OP powinno wyłączyć użycie 'goto' :) – 0decimal0

+2

Grumble: to też silny! Istnieją platformy, w których 'fflush (stdin)' jest w pełni zdefiniowany (jako niestandardowe rozszerzenie na tej platformie). Podstawowym przykładem jest dobrze znana rodzina systemów znanych jako system Windows. Zobacz specyfikację Microsoft ['fflush()'] (http://msdn.microsoft.com/en-us/library/9yky46tz.aspx): ** Jeśli strumień jest otwarty do wprowadzania, 'fflush' czyści zawartość bufor. ** –

+0

@ JonathanLeffler Ok! teraz mogę przypomnieć W przeszłości z turbo-C pod DOS na uniwersytecie użyłem 'fflush (stdin)'. I nie było źle! ~~ Dzięki! –

1

Jest to obejście, aby uniknąć nieskończonej pętli. Zamiast goto skorzystaj z pętli while:

do { 
    printf("\nEnter any integer: "); 
    x = scanf("%u",&a); 

    printf("%u",a); 
    if(x == 0) 
    { 
      char c; 
      printf("hit any key \n"); 
      c = getchar(); 
    } 

    } while(x==0); 
+1

** Nie ** .... to jest poprawne –

+0

stev, 'x' ma przypisaną wartość zwróconą przez scanf(), to scanf nie skanuje wartości, która zwraca 0, czytaj: http://www.cplusplus.com/ reference/cstdio/scanf/ –

+0

Grijesh, Tak, nie przeczytałem jego pytania. scanf nie zwróci EOF, dopóki strumień wejściowy nie zostanie zamknięty - to znaczy, że konsola zostanie zamknięta. Więc działa w nieskończoną pętlę. – stev

Powiązane problemy