2016-07-11 8 views
5

Ich habe eine "Minuten" Variable, die ich möchte der Benutzer eine positive Zahl eingeben.Eingabe einer Zeichenfolge in scanf mit einer while <0 Bedingung verursacht Endlosschleife

int main(void) 
{ 
    float minutes; 
    minutes = -1; 
    printf("Find out how many bottles worth of water your showers use!\n"); 
    printf("How many minutes do you spend in the shower? "); 
    scanf("%f", &minutes); 
    while(minutes < 0) 
    { 
     printf("Please enter a positive number: "); 
     scanf("%f", &minutes); 
    } 
} 

Es funktioniert wie für Zahlen vorgesehen. Wenn Minuten> = 0, akzeptiert es es, und wenn Minuten < 0 fragt es weiter. Wenn ich eine Zeichenfolge eingibt, wird sie unendlich verschachtelt

printf("Please enter a positive number: "); 

und gibt mir nie eine Chance, einen neuen Wert einzugeben. Warum ist das und wie kann ich es beheben? Vielen Dank!

+0

Was haben Sie mit diesem Programm vor? Was meinst du mit negativen und positiven Minuten? – user3078414

+0

Beachten Sie, dass 'scanf' nicht der sicherste Weg ist, um Eingaben zu erhalten, vor allem, da Sie mit den verschiedenen Eingabemöglichkeiten umgehen möchten. Siehe die akzeptierte Antwort [hier] (http://stackoverflow.com/questions/2430303/disadvantages-of-scanf) – iRove

+0

Warum wird der Titel so formuliert, als wäre das ein Fehler in C? – cat

Antwort

6

Wenn Sie keinen numerischen Wert eingeben, bleibt das, was Sie schreiben, im Eingabepuffer. Sie können dies überprüfen, indem Sie den Rückgabewert scanf lesen, der die Anzahl der gelesenen Elemente angibt. Wenn es 0 ist, können Sie getchar verwenden, um Zeichen bis zum nächsten Newline zu lesen, um den Puffer zu leeren.

int main(void) 
{ 
    int rval, c; 
    float minutes; 
    minutes = -1; 
    printf("Find out how many bottles worth of water your showers use!\n"); 
    printf("How many minutes do you spend in the shower? "); 
    rval = scanf("%f", &minutes); 
    if (rval == 0) { 
     while (((c = getchar()) != '\n') && (c != EOF)); 
    } 
    while(minutes < 0) 
    { 
     printf("Please enter a positive number: "); 
     rval = scanf("%f", &minutes); 
     if (rval == 0) { 
      while (((c = getchar()) != '\n') && (c != EOF)); 
     } 
    } 
} 
+0

Wo deklarieren und setzen Sie 'rval' im ersten Durchlauf? – user3078414

+0

@ user3078414 Verpasste eine Kopie/einfügen dort. Fest. – dbush

+0

Große Lösung. +1 für die Verwendung von 'getchar', das ist die POSIX-konforme Art, den Puffer zu löschen –

2

Der %f Konvertierungsspezifizierer sagt scanf Eingang aufhören zu lesen, sobald es ein Zeichen sieht, die nicht Teil einer juristischen Gleitkommazahlen konstant ist (dh etwas, das keine Ziffer, Komma, oder unterschreiben). Dieses schlechte Zeichen wird im Eingabestrom gelassen, so dass der nächste Aufruf an scanf fehlschlägt, und der nächste, und der nächste, usw.

Sie sollten immer den Rückgabewert von scanf überprüfen - es wird Ihnen sagen, wie viele Elemente waren erfolgreich aus dem Eingabestream gelesen und zugewiesen. In diesem Fall erwarten Sie ein einzelnes Element, daher sollten Sie einen Rückgabewert von 1 erhalten. Wenn Sie einen Rückgabewert von 0 erhalten, bedeutet dies, dass die Eingabe kein richtiger Fließkommawert ist und dass eine fehlerhafte Eingabe erforderlich ist irgendwie geklärt werden. Hier ist eine mögliche Lösung:

if (scanf("%f", &minutes) == 1) 
{ 
    // process minutes as normal 
} 
else 
{ 
    // clear everything up to the next whitespace character 
    while (!isspace(getchar())) 
    ; // empty loop 
} 

Das einzige Problem dabei ist, dass scanf Art stumm ist, und wenn Sie so etwas wie 123fgh geben, wird es konvertieren und die 123 zuweisen, während fgh in dem Eingangsstrom zu verlassen; Sie würden wahrscheinlich die gesamte Eingabe komplett ablehnen.

Eine Lösung ist die Eingabe als Text zu lesen, und es dann strtod mit konvertieren:

char buffer[BUFSIZE]; // where BUFSIZE is large enough to handle expected input 
... 
if (fgets(buffer, sizeof buffer, stdin)) 
{ 
    char *chk; // chk will point to the first character *not* converted; if 
      // it's anything other than whitespace or the string terminator, 
      // then the input was not a valid floating-point value. 
    double tmp = strtod(buffer, &chk); 
    if (isspace(*chk) || *chk == 0) 
    { 
    minutes = tmp; 
    } 
    else 
    { 
    // input was not a proper floating point value 
    } 
} 

Dies den Vorteil nicht Mist in dem Eingangsstrom verlassen hat.

+0

Hinweis: Dieser Code würde Eingaben wie '" 123 abc "' als gültige Eingabe akzeptieren. Dennoch ist die Verwendung von 'fgets()' ein guter Ansatz. – chux

Verwandte Themen