cin>>zahl; überprüfen, dass da nur eine zahl und nix anderes drin steht.



  • Ich würde sagen: lass den pathologischen Fall "77street" aus Deinem Beispiel links liegen.
    Sonst bist Du schnell da, dass Du ein user-interface nachprogrammierst, und da gibt es schon welche.

    Ganz klassisch:

    #include <iostream>
    #include <limits>
    
    // loescht alles aus einem istream bis zum naechsten newline
    template<typename CharT, typename Traits=std::char_traits<CharT> >
    std::basic_istream<CharT, Traits>& purge(std::basic_istream<CharT, Traits>& in){
      in.clear();
      in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      return in;
    }
    
    int main(){
      int i=0;
      for(;;)
        if(std::cin >> i){
          std::cout << "echo: " << i << '\n';
          break;
        }
        else{
          std::cerr << "Fehler! (i: " << i << ")\n";
          std::cin >> purge;
        }
    }
    


  • Man kann auch so was wie '77street' als Fehleingabe abfangen:

    int t;
        for( bool skip = false; cout << "Geben sie die Tiefe des Pascalschen Dreiecks an: ", !(cin >> t) || t < 0 
            || ((skip = true, cin >> skipline) && cin.gcount() > 1); skip = false )
        {
            cout << (skip? "nur eine Zahl": "bitte eine positive Zahl eingeben") << endl;
            cin.clear(); // Fehlerflag reset
            if( !skip && !(cin >> skipline) ) // ggf. Rest der Zeile ignorieren
                throw runtime_error( "Fatal Error: 'cin' is bad" ); 
        }
        cout << "Die Tiefe des Pascalschen Dreiecks ist " << t << endl;
    

    .. erfordert die includes <iostream>, <limits>

    Im Übrigen würde Dein Ansatz oben mit der Funktion 'leseZahl' auch in Java implementiert so nicht funktionieren.



  • skipline vergessen .. sieht so aus:

    std::istream& skipline( std::istream& in )
    {
        return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
    }
    


  • Darkangel1208 schrieb:

    Daher bringt mir dies auch nix

    int leseZahl()
    {
    	int zahl;
    	cin>>zahl;
    	if(cin.fail())
    	{
    		cout << "das war keine Zahl!" << endl;
    		cin.clear();
    		cin>>zahl;
    	}
    	return zahl;
    }
    

    Natürlich bringt es was. Ein bisschen weniger naiv sein und ein bisschen mehr nachdenken zahlt sich manchmal aus.
    Wieso sollte beim 2. Versuch nicht nochmal ein Eingabefehler kommen können?

    int leseZahl()
    {
    	for (;;)
    	{
    		int zahl;
    		cin >> zahl;
    		if (cin) // == if (!cin.fail())
    			return zahl;
    		else if (cin.eof())
    			throw std::runtime_error("f*ck this shit");
    
    		cout << "das war keine Zahl!" << endl;
    		cin.clear();
    	}
    }
    

  • Mod

    Das endet jetzt aber in einer Endlosschleife, wenn man keine Zahl eingibt.



  • ARGH, ja, sorry.
    Das kommt davon wenn man seinen Code nicht ausprobiert bevor man postet.
    Und da ich kaum jemals was mit iostreams mache...

    Nach dem cin.clear() muss also doch noch das cin.ignore(std::numeric_limits< std::streamsize >::max(), '\n') hin.

    Und dann sind wir im Prinzip bei dem was Werner schon geschrieben hat...



  • Sorry das ich mich jetzt erst melde, doch mein Job neben der uni hat mich sehr beansprucht. Zum teil verstehe ich eure Antworten aber leider sind das keine Try-catch lösungen. Aber wie sollen das Problem ja mithilfe von try und catch lösen. ergo...

    naja zumidest bin ich soweit, das er alles abfängt was mit einem buchstaben anfängt. doch eofbit bekomm ich nicht hin als wenn jemand eingiebt 3f oder 3,2 oder 3.4
    Ich bin zwar der meinung dass der code das auch abfangen müsste aber tu er nicht. könnte daran liegen da ja eofbit auch failbit setzt..?

    int Eingabe()
    {
    	std::cin.exceptions ( ifstream::eofbit | ifstream::failbit | ifstream::badbit );
    	int zahl;
    	do
    	{
    		try
    		{
    			cin>>zahl;
    
    		}
    		catch(iostream::failure e)
    		{
    			//cout << e.what();
    			cout << "Das war keine Zahl!" << endl;		
    		}
    		cin.sync();
    		cin.clear();
    		if (zahl<1)
    			cout<<"Die Zahl muss groesser 0 sein!";
    	}while(zahl<1);
    	return zahl;
    }
    

    diesen code habe ich im netz gefudnen und funzt erste sahne nur eben leider auch nicht try catch und auf anhieb leichter für mich zu verstehen, als eure beiträge sorry ( ich setz mich grad mit skip auseinander und skip? im code. Wär nur blöd wenn ich es dann versteh und es mir nix bringt.)

    int Eingabe()
    {
    	int zahl;
    	bool fertig = false;
        do {
            string eingabe;
            getline(cin, eingabe);
    
            istringstream converter(eingabe);
            converter >> zahl;
            if (converter.fail())     // sind Fehlerflags gesetzt?
                cout << "das war keine Zahl!" << endl;
            else {
                converter >> ws;      // ws verschluckt Leerzeichen -- und
                                      // setzt eof, wenn erreicht.
                if (!converter.eof()) // das Ende des streams ist noch nicht erreicht?
                    cout << "das fing an wie eine Zahl, war aber keine!" << endl;
                else
                    fertig = true;    // ansonsten ist alles gut.
            }
        }
        while (!fertig);
    	cin.sync();
    	cin.clear();
    	return zahl;
    }
    

    Morgen ist leider schon abgabe 😞



  • Darkangel1208 schrieb:

    Aber wie sollen das Problem ja mithilfe von try und catch lösen.

    Mein Beileid. Das ist so mit der schlimmste Missbrauch von Exceptions.

    Exceptions werden für unerwartete Ausnahmen gebraucht. Für Fälle, mit denen nicht gerechnet wird.

    I/O ist hier genau das Gegenteil. Da wird mit Fehleingaben gerechnet.

    Dein Code vom Netz ist der "Anfängerweg", es wird eine Zeile eingelesen und dann geparst. Furble Wurble und Werner machen das etwas geschickter. Finde heraus, was std::cin.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); macht, das fehlt nämlich in deinem Code.


  • Mod

    Mit Exceptions löst sich das Problem doch fast selbstständig:
    http://www.cplusplus.com/reference/ios/ios/exceptions/



  • SeppJ schrieb:

    Mit Exceptions löst sich das Problem doch fast selbstständig:
    http://www.cplusplus.com/reference/ios/ios/exceptions/

    Das kennt er schon (siehe ersten Codeblock in seinem letzten Post). Er schafft nur nicht, im Fehlerfall den Buffer zu leeren, dafür benötigt er das cin.ignore(...) .



  • hmm hmmmmmmmm

    kann mir einer vielleicht den Beitrag von Werner_logoff auseindernehmen?
    ich kenne die schreibweise der For-schleife so nicht und finde sie auch nicht im internet

    for(bool skip=false;!(cin >> t) || t <= 0|| ((skip = true, cin >> skipline) && cin.gcount() > 1); skip = false )
    

    das das cout

    cout << (skip? "nur eine Zahl": "bitte eine positive Zahl eingeben") << endl;
    

    das selbe ist wie

    if (skip==true)
    			cout<<"nur eine Zahl\n";
    		else
    			cout<<"bitte eine positive Zahl eingeben\n";
    

    habe ich schon herausgefunden. aber beo der For schleife hört es auf. Ich kann ja keinen Code nutzen den ich nicht verstehe.


  • Mod

    Das ist das gleiche for wie sonst auch. Orientiere dich an den ';':

    Ganz links steht also eine Initialisierung bool skip=false; Das verstehst du.

    Ganz rechts steht das was nach jedem Durchlauf gemacht werden soll: skip = false . Das verstehst du auch.

    Hinter der for-Schleife stehen die Anweisungen, hier nicht gezeigt, daher nehme ich mal an, die verstehst du ebenfalls.

    Und in der Mitte, das verstehst du ohne Erklärung wahrscheinlich nicht, steht wie immer die Schleifenbedingung:
    !(cin >> t) || t <= 0|| ((skip = true, cin >> skipline) && cin.gcount() > 1) Das ist ein einziger, großer Ausdruck. Nehmen wir ihn auseinander:
    Auf oberster Ebene sehen wir drei logische ODER "||". Diese verknüpfen drei Ausdrücke: !(cin >> t) , t <= 0 und ((skip = true, cin >> skipline) && cin.gcount() > 1) . Logisches UND und ODER haben in C++ (und vielen anderen Sprachen) folgende, sehr wichtige Eigenschaft, die du dir jetzt erst einmal anliest:
    http://en.wikipedia.org/wiki/Short-circuit_evaluation
    Aha! 💡 Der zweite Ausdruck wird also nur angeguckt, wenn der erste false ist und der dritte wird nur angeguckt, wenn die ersten beiden false sind.

    Der erste Ausdruck: !(cin >> t)
    Das sieht aus wie eine Leseanweisung, ist es auch. Folgende wichtige Eigenschaft aller Leseanweisungen (kennst du hoffentlich schon): Sie geben den Stream selbst als Rückgabewert. Und Eigenschaft von Streams (kennst du auch schon): Wenn man sie logisch auswertet sind sie true, wenn alles in Ordnung ist und false, wenn irgendwann etwas (hier eine Leseaktion) schiefgelaufen ist. Die for-Schleife wird also nicht betreten (beachte das "!"), wenn t erfolgreich gelesen wurde. Falls t erfolgreich gelesen wurde, wird der zweite Ausdruck angeguckt:

    t <= 0 . t wurde erfolgreich gelesen, gucken wir, ob es wirklich positiv ist. Wenn nicht, dann geht es in die Schleife, wenn doch, dann wird der dritte Ausdruck angeguckt:

    ((skip = true, cin >> skipline) && cin.gcount() > 1) . Wieder ein zusammengesetzter Ausdruck. Aus oberster Ebene sieht man ein logisches UND, das die Ausdrücke (skip = true, cin >> skipline) und cin.gcount() > 1 verknüpft. Man behalte die Eigenschaft des UND im Hinterkopf, der zweite Ausdruck wird nur angesehen, wenn der erste wahr ist. Zum ersten Ausdruck:
    (skip = true, cin >> skipline) . Dies sind wieder zwei Ausdrücke, dieses Mal mit dem Kommaoperator verknüpft. Der macht, dass beide Ausrücke von links nach rechts ausgewertet werden, aber der Gesamtausdruck hat hinterher den Wert von dem Ausdruck ganz rechts. Hier wird also skip auf true gesetzt und dann ein cin >> skipline ausgeführt. Der Rückgabewert des Ausdrucks ist also der Status von cin nach skipline. Ist cin im Fehlerzustand, dann ist es false und somit der Gesamtausdruck auch false und die Schleife bricht ab. Ist hingegen alles in Ordnung, dann wird cin.gcount() > 1 geprüft. Guck mal in eine Referenz dazu:
    http://www.cplusplus.com/reference/istream/istream/gcount/
    Aha, es prüft also ob das ignore in skipline mehr als ein Zeichen übersprungen hat. Wenn ja, dann ist der Gesamtausdruck wahr und es geht in die Schleife, wenn nein, dann bricht die Schleife ab.



  • Darkangel1208 schrieb:

    Sorry das ich mich jetzt erst melde, doch mein Job neben der uni hat mich sehr beansprucht. Zum teil verstehe ich eure Antworten aber leider sind das keine Try-catch lösungen. Aber wie sollen das Problem ja mithilfe von try und catch lösen. ergo...

    Aha... try&catch müssen also Teil der Lösung sein. Das konnte ja niemand ahnen.
    Da ich mir nicht vorstellen kann, dass es explizit um die io-Exceptions geht: Schreib doch Deine Tests und exceptions selber. Dass Du eine Eingabe von cin in einen string bekommst mit ( getline() , oder operator>> ) weisst Du. Danach musst Du Dir nur noch den Inhalt ansehen und "Zack die Bohne! Testat in der Tasche!", oder?

    #include <iostream>
    #include <string>
    #include <cctype>
    #include <sstream>
    
    struct not_an_integer{};  // meine Exception
    
    std::string::const_iterator all_digits(const std::string& s){
            std::string::const_iterator first = s.begin();
            for( ; first!=s.end(); ++first ){
                    if(std::isdigit(*first) == 0)
                            break;
            }
            return first;
    }
    
    int main(){
            std::string s;
            std::cin>>s;
            try{
                    if(all_digits(s) != s.end())
                            throw not_an_integer();
                    else{
                            int i;
                            std::istringstream converter(s);
                            converter >> i;
                            std::cout << i << std::endl;
                    }
            }
            catch(const not_an_integer& s){
                    std::cerr << "not_an_integer exception caught.\n";
                    return -1;
            }
    
    }
    

Anmelden zum Antworten