2017-01-24 6 views
-3

GELöST „verpasste die Rückkehr nach der Schleife nach einem korrekten Wert eingegeben wurde“C++ Funktion gibt nan statt Doppel

Ich benutze scanf_s Eingabe von der Konsole zu erhalten. Ich schrieb eine Funktion, die die Eingabe überprüft, und wenn sie falsch ist, fordert sie eine erneute Eingabe an.

Wenn ich einen korrekten Wert das erste Mal alles in Ordnung ist. Wenn ich den Wert ein zweites Mal innerhalb der Funktion eingeben muss, ist alles in Ordnung, aber anstatt diesen Wert zurückzugeben, gibt die Funktion NaN zurück. Warum geht der doppelte Wert nur dann verloren, wenn ich scanf_s zweimal verwende?

Wenn ich die Eingabe aufrufen und einen korrekten Wert eingeben, wird ein Doppel zurückgegeben. Wenn ich einen Wert kleiner oder gleich 0 gebe, muss ich den Wert erneut eingeben, aber diesmal wird NaN zurückgegeben. Beim Debuggen kann ich sehen, dass Eingabe noch ein Double ist.

double input() { 
    int n = -1; 
    double eingabe = 0.0; 

    scanf_s("%lf", &eingabe); 

    clearBuffer(); 
    if (eingabe <= 0.0) 
    { 
     do 
     { 
      printf("Invald input"); 
      printf("Try again: "); 

      n = scanf_s("%lf", eingabe); 
      clearBuffer(); 
     } while (eingabe <= 0.0); 
    } 
    else 
    { 
     return eingabe; 
    } 
} 

void clearBuffer() { 
    //alles aus dem Buffer lesen bis man bei EOF (END OF FILE) ankommt 
    int c; 
     while ((c = getchar()) != EOF) { 
      if (c == '\n') 
       break; 
     } 
} 
+0

Wenn Sie als C++ kompilieren, warum nicht 'std :: cin' anstelle von' scanf_s' und 'std :: cout' anstelle von' printf' verwenden? –

+1

Was hat Ihr Debugger Ihnen gesagt? Haben Sie gesehen, dass Ihre Rückmeldung wie erwartet getroffen wurde? – UKMonkey

+1

Follow up - Hat Ihr Compiler Sie über Ihre Funktion input() gewarnt? – UKMonkey

Antwort

1

Sie geben den Wert nicht innerhalb if (eingabe <= 0.0) zurück.

Sie müssen Ihren Code neu schreiben, damit der eingabe immer zurückgegeben wird.

Wie so:

if (eingabe <= 0.0) 
{ 
    do 
    { 
     printf("Invald input"); 
     printf("Try again: "); 

     n = scanf_s("%lf", &eingabe); 
     clearBuffer(); 
    } while (eingabe <= 0.0); 
} 
return eingabe; 

Oder etwa so:

if (eingabe <= 0.0) 
{ 
    do 
    { 
     printf("Invald input"); 
     printf("Try again: "); 

     n = scanf_s("%lf", &eingabe); 
     clearBuffer(); 
    } while (eingabe <= 0.0); 
    return eingabe; 
} 
else 
{ 
    return eingabe; 
} 

Meiner Meinung nach, erster Fall ist besser.

bearbeiten

Hier machte ich einige Refactoring mit Ihrem Code. Nicht jeder wird es mögen, wegen while(true) Zeug und continue und return nicht am Ende einer Funktion. Aber zumindest ist es in C++ geschrieben und meiner Meinung nach ist es ziemlich natürlich und liest deutlich.

#include <iostream> 
#include <limits> 

double input() { 
    double eingabe; 

    while (true) { 
     std::cout << "Enter a positive real number: "; 
     std::cin >> eingabe; 

     if (std::cin.fail()) { 
      std::cout << "Number expected." << std::endl; 
      std::cin.clear(); 
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
      continue; 
     } 

     if (eingabe <= 0) { 
      std::cout << "Positive number expected." << std::endl; 
      continue; 
     } 

     return eingabe; 
    } 
} 
+1

Plus, 'wenn (x) do {...} while (x)' ist äquivalent zu 'while (x) {...}' und viel besser lesbar. – YSC

+0

und da wir nichts mit dem 'n' machen, könnten wir es einfach löschen – Exagon

+1

Zusammenfassend - der Grund für den Fehler ist, dass die Regel" nicht wiederholen "verletzt wurde und ein Fehler beim Wiederholen gemacht wurde. – UKMonkey

0

Ich denke da einige Probleme in Ihrer Lösung diskutiert werden.

Erstens geben nicht alle Steuerpfade einen Wert zurück, der wahrscheinlich zu unerwünschten Ergebnissen der Funktion input führt; Dein Compiler hätte dich warnen sollen.

Zweitens basiert Ihre Fehlerbedingung auf dem doppelten Wert, den ein Benutzer in dem Sinne eingibt, dass negative Zahlen oder 0 als Fehler behandelt werden. Wenn Sie auch negative Zahlen oder 0 eingeben möchten, muss dieser Ansatz überarbeitet werden. Sie sollten den Rückgabewert scanf verwenden, der angeben kann, ob das angegebene Format erfolgreich gelesen wurde.

Drittens Sie verwenden scanf_s, das heißt die „sichere“ Version von scanf in dem Sinne, dass scanf_s die Zeichen auf einen Puffer geschrieben begrenzen könnten; Dies ist hier aus zwei Gründen nicht sinnvoll: (a) Sie geben kein Limit für den Puffer als zusätzliches Argument an und (b) das Scannen %lf ist sowieso durch den Datentyp double begrenzt.Confer zum Beispiel scanf_s -Referenz auf msdn:

Gegensatz Scanf und wscanf, scanf_s und wscanf_s erfordern die Puffergröße für alle Eingangsparameter des Typs C angegeben werden, C, S, S, oder String Kontrollsätze, die in [] eingeschlossen sind. Die Puffergröße in Zeichen als zusätzlichen Parameter unmittelbar nach dem Zeiger auf den Puffer oder variable

Vierte geführt wird, ist das Konstrukt wahrscheinlich ein wenig zu kompliziert, wie zum Beispiel Aussagen double eingabe = 0.0 gefolgt von if (eingabe <= 0.0) nicht Sinn machen.

Lassen Sie mich eine „kürzere“ Lösung für die Funktion vorschlagen input:

double input() { 

    double eingabe = 0.0; 
    int validInput = 0; 
    do { 
     if (scanf("%lf", &eingabe) == 1 && eingabe > 0) 
      validInput = 1; 
     else { 
      printf("Invald input\n" 
       "Try again:"); 
      scanf("%*[^\n]\n"); 
     } 
    } 
    while (!validInput); 
    return eingabe; 
} 

Beachten Sie, dass Anweisung scanf("%*[^\n]\n") alle Zeichen bis zum nächsten \n einschließlich der \n verbraucht, ohne mit einem Puffer schriftlich (* in das exprimierte Format).