Eingabe überprüfen klappt nicht wie geplant ?-)



  • Hi!
    Das folgende Code-Stueck sollte eigentlich verhindern, dass der User etwas anderes als einen Integer eingibt, aber es klappt nicht wie geplant:

    while ((cout << "where would you like to place the next coin: ")  && !(cin >> chosenSlot))
    	{
    		cin.clear();
    		cin.ignore(cin.rdbuf()->in_avail());
    		cout << "\n!!! sorry, but that's not a valid slot! !!!\n\n\n";
    	}
    

    Allerdings sieht die Ausgabe in etwa so aus:

    Player 1, it's your turn!
    where would you like to place the next coin: e
    !!! sorry, but that's not a valid slot! !!!
    
    where would you like to place the next coin: 
    !!! sorry, but that's not a valid slot! !!!
    
    where would you like to place the next coin: 
    !!! sorry, but that's not a valid slot! !!!
    
    where would you like to place the next coin: 
    !!! sorry, but that's not a valid slot! !!!
    
    [...]
    

    hab ich irgendwas uebersehen? Der Code sollte ja eigentlich so funktionieren, dass bei ungueltiger Eingabe (z. B. einem char) der cin-Buffer geleert wird und der User nochmal um eine Eingabe gebeten wird. Und das so lange, bis die Eingabe ok ist...

    Allerdings geht das Programm in eine Endlosschleife, wenn keine gueltige Eingabe erfolgt, und bietet dem User nicht die Gelegenheit, nochmal was einzugeben...

    Wo hab ich den Fehler gemacht? 😕



  • 1:1 übernommen und bei mir funktioniert das aber wunderbar 😕
    where's the prob?



  • hmm... bei mir funktionierts leider nicht ganz wie geplant... 😕



  • du nutzt doch g++? da hat hume sikkins doch mal gesagt das man da noch cin.sync() brauch.



  • Blue-Tiger schrieb:

    Wo hab ich den Fehler gemacht?

    cin.ignore(cin.rdbuf()->in_avail()); funktioniert nicht portabel, da in_avail() auf vielen Implementationen immer 0 zurückliefert.
    Versuch's mal so:

    while ((cout << "where would you like to place the next coin: ")  && !(cin >> chosenSlot))
    {
        cin.clear();
        while (cin.get() != '\n'); 
        cout << "\n!!! sorry, but that's not a valid slot! !!!\n\n\n";
    }
    


  • hmm.... im VC7 kompiliert das Ganze und funktioniert auch so, wie's soll, im GCC 3.3.1 jedoch nicht.... kennt jemand Rat bzw. weiss, woran das liegen koennte?



  • HumeSikkins schrieb:

    Blue-Tiger schrieb:

    Wo hab ich den Fehler gemacht?

    cin.ignore(cin.rdbuf()->in_avail()); funktioniert nicht portabel, da in_avail() auf vielen Implementationen immer 0 zurückliefert.
    Versuch's mal so:

    while ((cout << "where would you like to place the next coin: ")  && !(cin >> chosenSlot))
    {
        cin.clear();
        while (cin.get() != '\n'); 
        cout << "\n!!! sorry, but that's not a valid slot! !!!\n\n\n";
    }
    

    ich dachte, in_avail() gibt zurueck wieviel noch im Buffer ist? Wenn dem nicht so ist, was ist dann Sinn & Zweck von in_avail()?

    @falsche antwort:
    mit cin.sync(); am Ende gehts, aber was genau macht cin.sync() eigentlich?



  • Ich würde nen gebufferten Input machen - eine Zeile in einen String einlesen und den gesondert behandeln. Etwa so:

    #include <iostream>
    #include <sstream>
    #include <string>
    
    using namespace std;
    
    int main() {
      int x;
      bool read_success = false;
    
      do {
        string line;
        stringstream sstr;
    
        cout << "Bitte geben Sie eine Zahl ein: " << flush;
        getline(cin, line);
    
        sstr.str(line);
        read_success = sstr >> x;
      } while(!read_success);
    
      cout << "Sie haben " << x << " eingegeben." << endl;
    }
    


  • Blue-Tiger schrieb:

    ich dachte, in_avail() gibt zurueck wieviel noch im Buffer ist?

    in_avail liefert die Zeichen die noch im Lesepuffer stehen (also egptr() - gptr()) oder aber, falls hier keine Zeichen mehr stehen, einen "Schätzung" wieviele Zeichen noch im physikalischen Strom sind oder -1, falls keine solche Schätzung möglich ist.
    Eine Implementation die keinen zusätzlichen Lesepuffer für cin verwendet kann also ohne Probleme immer 0 bzw. -1 zurückliefern.

    mit cin.sync(); am Ende gehts, aber was genau macht cin.sync() eigentlich?

    Das Verhalten von sync() ist nur für *Ausgabe*ströme spezifiziert. Stroustrup und einige Iostream-Implementation verbinden mit sync() auf Eingabeströmen aber ein "flush" des Strompuffers.



  • Also nix von wegen portabler C++ Standardbibliothek? 😕

    Blue-Tiger: probier's doch mal mit den guten alten fgets() und sscanf() Funktionen:

    #include <stdio.h>  // bzw. <cstdio> fuer standardkonforme
                        // Entwicklungsumgebungen
    
    // ...
    
    // vorher Text ausgeben "Bitte Zahl eingeben: " oder sowas
    char buf[1024]; int zahl = 0;
    for (;;) {
       if ( fgets( stdin, buf, sizeof(buf) ) == 0 ) break; // Ctrl-D oder Ctrl-Z
       if ( sscanf( buf, "%d", &zahl ) == 1 ) break; // Zahl eingegeben
       // sonst schreibe "Es wurde keine Zahl eingegeben!"
    }
    


  • Power Off schrieb:

    Also nix von wegen portabler C++ Standardbibliothek? 😕

    Doch sicher. Es ist nur nix mit "ich-wünsch-mir-meine-Welt-wie-sie-mir-gefällt". Wenn du auf das vertraust, was dir der Standard garantiert bleibst du portabel. Wenn du auf das vertraust, was du hoffst das passiert (bzw. auf das was dir Implementation X als Komfortfunktionalität anbietet), dann bekommst du natürlich Probleme.

    Btw: Das ist bei den C-Streams auch nicht anders. Wenn du dort z.B. darauf baust, dass fflush(stdin) den Eingabestrom leert (was es in bestimmten Implementationen tut), stehst du letztlich vor einem ähnlichen Problem, da der C-Standard dies nicht garantiert. Vielmehr sagt er, dass es zu undefiniertem Verhalten führt.



  • Ich hab das selbe Problem wie Blue Tiger, würde mich über sowas wie eine eindeutige Lösung freuen...
    Was ich auch noch super fände, wäre, wenn man dieses Auf-Integer-Überprüfen gleichzeitig mit einer Prüfung, ob der Integer zwischen bestimmten Grenzen, zB zwischen 1 und 10 liegt, verbinden könnte. Geht das möglichst elegant?
    mfG,
    Matthias



  • wie wäre es mit:

    const int MIN=1, MAX=10;
    int chosenSlot;
    
    while( (cout << "where would you like to place the next coin: ") && !(cin >> chosenSlot)
            || (chosenSlot<MIN) || (chosenSlot>MAX) )
    { 
            cin.clear(); 
            cin.ignore(); 
            cout << "\n!!! sorry, but that's not a valid slot! !!!\n\n\n"; 
    }
    

    irgendwie verstehe ich das Problem nicht 😉 :p



  • freshman schrieb:

    cin.ignore();
    [/cpp]

    Damit ignorierst du maximal ein Zeichen. Häufig viel zu wenig.

    Dann doch eher:

    cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
    

    was dann aber letztlich auch nichts weiter ist als:

    while (cin.get() != '\n');
    

Anmelden zum Antworten