Abfangen von falschen cin Eingaben?



  • Hallo Leute, ja der Titel ist nicht wirklich aussagekräftig, aber besseres ist mir nicht eingegefallen.

    Ich habe eine Klasse erstellt die drei double Werte speichern soll.
    Die Eingabe findet über cin statt, wenn man nun in der cin-Eingabe ein Buchstaben eingibt führt das zum Absturz des Programms.

    Gibt es eine Möglichkeit bei der Eingabe über cin diese ungewollten Eingaben abzufangen, also erkennen zu können und dann eine Fehlermeldung ausgeben?
    Das ganze sollte bitte ohne Exceptions möglich sein, diese "darf" ich noch nicht kennen.

    Grüße Blade


  • Administrator

    Du kannst nach jeder Leseoperation prüfen, ob der Stream noch gültig ist. Entweder über die Methode good (http://www.cplusplus.com/reference/iostream/ios/good/) oder indem du den Stream direkt hinsetzt (http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/, bzw. http://www.cplusplus.com/reference/iostream/ios/operatornot/). Gerade letzteres ist praktisch, damit man die Leseoperation direkt als Bedingung hinschreiben kann.

    Falls ein Fehler auftrat, kannst du über die Methode clear (http://www.cplusplus.com/reference/iostream/ios/clear/) die Fehlerflags zurücksetzen. Solange Fehlerflags gesetzt sind, scheitern alle Leseoperationen. Auch sinnvoll ist es, den Eingabepuffer zu leeren, um die ungültigen Eingaben zu entfernen. Dazu kann man die Methode ignore (http://www.cplusplus.com/reference/iostream/istream/ignore/) verwenden. Um herauszufinden, wieviel noch im Puffer ist, kann man den Puffer mit rdbuf (http://www.cplusplus.com/reference/iostream/ios/rdbuf/) holen. Dort gibt es dann die Methode in_avail (http://www.cplusplus.com/reference/iostream/streambuf/in_avail/).

    Grüssli



  • Weiß nicht ob folgende Methode einfach aus Draveres Beitrag abzuleiten ist:

    double myd;
    
     if (cin >> myd)
        cout << "OK\n";
     else
        cout << "nicht OK\n";
    

    Aber, du musst bedenken, dass eine Eingabe wie 1234a nicht direkt zu einem Fehler führt. D.h. die 1234 geht in die double-Variable und das 'a' bleibt im Puffer und führt eventuell erst beim nächsten Einlesen zum Fehler.



  • Hmmm, das sieht schon ziemlich cool aus, aber mein Problem bleibt noch das Abfangen des Fehlers. Also das das Programm nicht abschmiert.
    In den oben genannten Vorschlag wurde das mit clear() gelöst, leider scheind das bei mir nicht zu funktionieren, der Compilierer meldet als Fehler "unbekannten Bezeichner".

    Grüße Blade


  • Administrator

    Ich empfehle dir, dass du zumindest noch ein wenig Quellcode zeigst und den genauen Fehler hier reinschreibst. Ich glaube nämlich irgendwie, dass du die Methode clear falsch verwendest. Zudem muss es ja nicht nur clear sein, auch ignore und co sind wichtig, da sonst die fehlerhafte Eingabe im Stream verbleibt.

    Grüssli



  • #include <iostream>
    
    int main()
    {
        int eingabe;
        while(!(std::cin >> eingabe))
        {
            std::cout << "Falsche Eingabe!" << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<int>::max(),'\n');
        }
        std::cout << eingabe;
    }
    


  • wofür das ignore?



  • blade1982 schrieb:

    Hmmm, das sieht schon ziemlich cool aus, aber mein Problem bleibt noch das Abfangen des Fehlers.

    Musste nach dem Einlesen testen, ob der Puffer leer ist.



  • Heinzelmännchen! schrieb:

    wofür das ignore?

    Wofür ignore? Probiers halt aus und schau was passiert. Tipp : Stichwort Endlosschleife...



  • FreakY<3Cpp schrieb:

    Heinzelmännchen! schrieb:

    wofür das ignore?

    Wofür ignore? Probiers halt aus und schau was passiert. Tipp : Stichwort Endlosschleife...

    .. oder lies draveres post noch mal... 😛



  • So hier mal meine Lösung:
    (double spannung; double temperatur, int prozess)

    void CFaktoren::bestimmeFaktoren() {
       bool valid;
       do {
       cout << "Bitte geben sie die drei folgenden Parameter ein:" <<endl;
       cout << "Spannung (Werte zwischen 1.08V und 1.32V): ";
       if (cin >> spannung){}
       else {
          cin.clear();
          cin.ignore();
          spannung = -100;
       }
       cout << "Temperatur (Werte zwischen -25C und 125C) : ";
       if (cin >> temperatur){}
       else {
          cin.clear();
          cin.ignore();
          temperatur = -100;
       }
       cout << "Prozess (Werte koennen nur 1=slow 2=typical 3=fast sein) : ";
       if( cin >> prozess){}
       else {
          cin.clear();
          cin.ignore();
          prozess = 100;
       }
       if( spannung > 1.32 || 
           spannung < 1.08 || 
           temperatur > 125 ||
           temperatur < -25 ||
           prozess > 3 || 
           prozess < 1 ){
           valid = false;
           cout << endl;
           cout << "Achtung sie haben Paramter eingegeben die ausserhalb der Spezifikationen liegen" <<endl;
           cout << "Bitte geben sie die Werte erneut ein" <<endl;
           cout << endl;
       }
       else
          valid = true;   
       }
       while( valid == false ); 
       berechneSpannungsFaktor();
       berechneTemperaturFaktor();
       berechneProzessFaktor();
       ausgabeFaktoren();
       system("pause");
    }
    

    Es mag bestimmt nicht der schnellste oder optimalste Code sein, aber es sollte nun sein Zweck erfüllen.
    Danke an alle für die guten Tips und Vorschläge.



  • Dein Code geht nicht. Gebe ich bei der ersten Eingabe "erge" ein, überspringt er ALLE Eingaben und ich bekomme alle Ausgaben in die Konsole. Erst am Ende sagt er, das die Eingabe falsch war. Schau dir mein Code an, den ich auf der ersten Seite gepostet habe:

    FreakY<3Cpp schrieb:

    #include <iostream>
    
    int main()
    {
        int eingabe;
        while(!(std::cin >> eingabe))
        {
            std::cout << "Falsche Eingabe!" << std::endl;
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<int>::max(),'\n');
        }
        std::cout << eingabe;
    }
    

    Benutze ihn auch so wie er da steht, denn er ist richtig.



  • Hmm, ich habs wohl nicht richtig getestet....
    1 zu 1 kann ich das eh nicht übernehmen, aber kannst du mir bitte die Zeile 10 erläutern? Die Parameter von Ignore erklären sich mir nicht so recht.
    MFG Blade


  • Administrator

    Die Zeile 10 sollte eigentlich so aussehen:

    std::cin.ignore(std::cin.rdbuf()->in_avail());
    

    Hier werden einfach so viele Zeichen ignoriert ( ignore ), wie es noch im Puffer ( rdbuf holt den Puffer) des Streams hat ( in_avail gibt die Menge zurück).

    Da es aber anscheinend Implementationen von der Standardbibliothek gibt, welche dies nicht korrekt unterstützen, gibt es da einen Workaround und das ist die Lösung von FreakY<3Cpp.
    Dort ignoriert man die maximale mögliche Anzahl an Zeichen oder bis zu und mit einem Linefeed. Die Konsoleneingaben werden grundsätzlich alle mit einem Linefeed abgeschlossen, da der Benutzer <Enter> gedrückt hat, zum bestätigen der Eingabe.
    Ganz korrekt wäre hier eigentlich:

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

    std::numeric_limits ist eine Hilfsklasse, bzw. eine sogenannte Traitsklasse, um Informationen über den numerischen Typ zu erhalten:
    http://www.cplusplus.com/reference/std/limits/numeric_limits/

    War das verständlich genug?

    Grüssli



  • http://www.c-plusplus.net/forum/viewtopic-var-t-is-243173-and-highlight-is-ignore.html
    Da habe ich es schonmal gepostet und doch, du kannst ihn 1 zu 1 übernehmen.

    void CFaktoren::bestimmeFaktoren() 
    {
        bool valid;
        do 
        {
            cout << "Bitte geben sie die drei folgenden Parameter ein:" <<endl;
            cout << "Spannung (Werte zwischen 1.08V und 1.32V): ";
            while(!(cin >> spannung))
            {
                cout << "Falsche Eingabe!" << endl;
                cin.clear();
                cin.ignore(numeric_limits<int>::max(),'\n');
            }
            cout << "Temperatur (Werte zwischen -25C und 125C) : ";
            while(!(cin >> temperatur))
            {
                cout << "Falsche Eingabe!" << endl;
                cin.clear();
                cin.ignore(numeric_limits<int>::max(),'\n');
            }
            cout << "Prozess (Werte koennen nur 1=slow 2=typical 3=fast sein) : ";
            while(!(cin >> prozess))
            {
                cout << "Falsche Eingabe!" << endl;
                cin.clear();
                cin.ignore(numeric_limits<int>::max(),'\n');
            }
            if(spannung > 1.32 || spannung < 1.08 ||
               temperatur > 125 || temperatur < -25 ||
               prozess > 3 || prozess < 1 )
            {
               valid = false;
               cout << endl;
               cout << "Achtung sie haben Paramter eingegeben die ausserhalb der Spezifikationen liegen" <<endl;
               cout << "Bitte geben sie die Werte erneut ein" <<endl;
               cout << endl;
            }
            else
                valid = true;  
        }
        while( valid == false );
        berechneSpannungsFaktor();
        berechneTemperaturFaktor();
        berechneProzessFaktor();
        ausgabeFaktoren();
        system("pause");
    }
    


  • Hier mal in mein Programm eingeführt:
    Das (numeric_limits<int>::max(),'\n') führt zu einen kompilierer Fehler "bezeichner numeric_limits nicht gefunden"

    void CFaktoren::bestimmeFaktoren() {
       bool valid;
       do {
       cout << "Bitte geben sie die drei folgenden Parameter ein:" <<endl;
       cout << "Spannung (Werte zwischen 1.08V und 1.32V): ";
       while(! (cin >> spannung)){
          cin.clear();
          cin.ignore(cin.rdbuf()->in_avail());	
       }
       cout << "Temperatur (Werte zwischen -25C und 125C) : ";
          while(! (cin >> temperatur)){
          cin.clear();
          cin.ignore(cin.rdbuf()->in_avail());	
       }
       cout << "Prozess (Werte koennen nur 1=slow 2=typical 3=fast sein) : ";
       while(! (cin >> prozess)){
          cin.clear();
          cin.ignore(cin.rdbuf()->in_avail());
       }
       if( spannung > 1.32 || 
           spannung < 1.08 || 
           temperatur > 125 ||
           temperatur < -25 ||
           prozess > 3 || 
           prozess < 1 ){
           valid = false;
           cout << endl;
           cout << "Achtung sie haben Paramter eingegeben die ausserhalb der Spezifikationen liegen" <<endl;
           cout << "Bitte geben sie die Werte erneut ein" <<endl;
           cout << endl;
       }
       else
          valid = true;   
       }
       while( valid == false ); 
       berechneSpannungsFaktor();
       berechneTemperaturFaktor();
       berechneProzessFaktor();
       ausgabeFaktoren();
       system("pause");
    }
    

    Leider ist das Programm so nicht lauffähig, kompiliert wird es zwar aber es macht nicht mehr das was es sollte.
    MFG Blade



  • Dann schreib mal std:: vor numeric_limits. Und was genau macht es nicht was es aber machen sollte?



  • So ist sind nun schon 9 kompilierer Fehler:

    error C2039: 'numeric_limits': Ist kein Element von 'std'
    error C2065: 'numeric_limits': nichtdeklarierter Bezeichner
    error C2062: 'int'-Typ unerwartet
    Und die fehler jeweils für spannung, temperatur und prozess.
    Der namespace ist im übrigen mit using namespace std; schon abgedeckt.

    void CFaktoren::bestimmeFaktoren() {
       bool valid;
       do {
       cout << "Bitte geben sie die drei folgenden Parameter ein:" <<endl;
       cout << "Spannung (Werte zwischen 1.08V und 1.32V): ";
       while(! (cin >> spannung)){
          cin.clear();
          cin.ignore(std::numeric_limits<int>::max(),'\n');	
       }
       cout << "Temperatur (Werte zwischen -25C und 125C) : ";
          while(! (cin >> temperatur)){
          cin.clear();
          cin.ignore(std::numeric_limits<int>::max(),'\n');	
       }
       cout << "Prozess (Werte koennen nur 1=slow 2=typical 3=fast sein) : ";
       while(! (cin >> prozess)){
          cin.clear();
          cin.ignore(std::numeric_limits<int>::max(),'\n');
       }
       if( spannung > 1.32 || 
           spannung < 1.08 || 
           temperatur > 125 ||
           temperatur < -25 ||
           prozess > 3 || 
           prozess < 1 ){
           valid = false;
           cout << endl;
           cout << "Achtung sie haben Paramter eingegeben die ausserhalb der Spezifikationen liegen" <<endl;
           cout << "Bitte geben sie die Werte erneut ein" <<endl;
           cout << endl;
       }
       else
          valid = true;   
       }
       while( valid == false ); 
       berechneSpannungsFaktor();
       berechneTemperaturFaktor();
       berechneProzessFaktor();
       ausgabeFaktoren();
       system("pause");
    }
    

  • Administrator

    #include <limits>

    Grüssli



  • Jop, jetzt gehts. Danke
    Hier nochmal das vollständige Programm:

    void CFaktoren::bestimmeFaktoren() {
       bool valid;
       do {
       cout << "Bitte geben sie die drei folgenden Parameter ein:" <<endl;
       cout << "Spannung (Werte zwischen 1.08V und 1.32V): ";
       while(! (cin >> spannung)){
          cin.clear();
          cin.ignore(numeric_limits<int>::max(),'\n');
          cout <<"Eingabe falsch, bitte erneut eingeben: ";
       }
       cout << "Temperatur (Werte zwischen -25C und 125C) : ";
          while(! (cin >> temperatur)){
          cin.clear();
          cin.ignore(numeric_limits<int>::max(),'\n');	
          cout <<"Eingabe falsch, bitte erneut eingeben: ";
       }
       cout << "Prozess (Werte koennen nur 1=slow 2=typical 3=fast sein) : ";
       while(! (cin >> prozess)){
          cin.clear();
          cin.ignore(numeric_limits<int>::max(),'\n');
          cout <<"Eingabe falsch, bitte erneut eingeben: ";
       }
       if( spannung > 1.32 || 
           spannung < 1.08 || 
           temperatur > 125 ||
           temperatur < -25 ||
           prozess > 3 || 
           prozess < 1 ){
           valid = false;
           cout << endl;
           cout << "Achtung sie haben Paramter eingegeben die ausserhalb der Spezifikationen liegen" <<endl;
           cout << "Bitte geben sie die Werte erneut ein" <<endl;
           cout << endl;
       }
       else
          valid = true;   
       }
       while( valid == false ); 
       berechneSpannungsFaktor();
       berechneTemperaturFaktor();
       berechneProzessFaktor();
       ausgabeFaktoren();
       system("pause");
    }
    

Anmelden zum Antworten