Problem beim beenden einer cin Eingabe



  • Hallo zusammen! Bin Anfänger mit C++ und habe mich gerade im Forum angemeldet!
    Ich arbeite gerade ein bisschen mit dem Stroustrup Buch und hände gerade an einem Code fest! Das Programm ließt eine Reihe von Zahlen über cin in einen Vektor ein. Danach werden die Einträge des Vektors addiert. Danach soll der Benutzer eine weitere Zahl eingeben. Die Summe der Vektoreinträge wird dann durch diese Zahl geteilt und über cout ausgegeben. Erstmal der Code:

    #include "std_lib_facilities.h"
    
    int main()
    {
    	vector<double> temps;
    	double temp;
    	int divisor;
    
    	while (cin >> temp)
    		temps.push_back(temp);
    
    	double sum = 0;
    
    	for (int i = 0; i < temps.size(); ++i)
    		sum += temps[i];
    
    	cout << "Geben Sie einen Divisor ein!" << endl;
    
    	cin >> divisor;
    
    	cout << sum/divisor;
    
    	keep_window_open();
    }
    

    Nun das Problem: Ich gebe also eine Reihe von Werten ein, die dann in den Vektor eingelesen werden sollen. Danach drücke ich zum beenden der Eingabe strg + Z (Arbeite unter Windows) oder gebe einen nicht double Wert ein. Danach wird die Eingabe auch abgebrochen aber das Programm läuft einfach durch ohne mir die Chance zu geben über das zweite cin einen "Divisor" einzugeben!

    Könnt ihr mir helfen? Was mache ich falsch?
    Liebe Grüße



  • du hast noch was im Stream stehen was mit cin eingelesen wird, drum läuft das druch.

    bau mal

    std::cin.ignore(256, '\n')
    

    mit ein...


  • Mod

    Nachdem die Eingabe in Zeile 11 fehlschlägt (weil auf das Ende der Eingabe getroffen wurde), befindet sich der Stream cin in einem Fehlerzustand. Alle weiteren Operationen darauf werden ebenfalls fehlschlagen, so lange man nicht signalisiert hat, dass man sich um die Fehlerursache gekümmert hat. Hier ist das Beheben der Fehlerursache jedoch ganz einfach: Es gibt nichts zu tun! Man kann also einfach den Fehlerstatus aufheben und der Stream ist dann bereit für weitere Operationen. Den Fehlerstatus von cin kann man mittels cin.clear() aufheben, was entsprechend irgendwo zwischen Zeile 12 und 21 erfolgen muss.


  • Mod

    cin_clear schrieb:

    du hast noch was im Stream stehen was mit cin eingelesen wird, drum läuft das druch.

    bau mal

    std::cin.ignore(256, '\n')
    

    mit ein...

    Nein.



  • Vielen Dank SeppJ das hat geholfen!
    Aber nur wenn ich das erste cin mit strg + Z beende!
    Wie erreiche ich, dass durch die Eingabe von zb "e" die Eingabe beendet wird?


  • Mod

    seppinobis schrieb:

    Vielen Dank SeppJ das hat geholfen!
    Aber nur wenn ich das erste cin mit strg + Z beende!
    Wie erreiche ich, dass durch die Eingabe von zb "e" die Eingabe beendet wird?

    In dem Fall ist das 'e' noch im Stream, da es nicht als Zahl gelesen werden konnte. Wenn du beim nächsten Mal wieder versuchst, eine Zahl zu lesen, wird das entsprechend wieder scheitern.

    Dies ist, wo solche Dinge wie das ignore, das cin_clear gezeigt hat, ins Spiel kommen. Damit kannst du das 'e' aus dem Stream entfernen. Ein einfaches ignore überspringt ein Zeichen. Ein ignore mit einer Zahl als Argument, überspringt diese Anzahl Zeichen. Ein ignore mit einer Zahl und einem Buchstaben als Argument (wie von cin_clear gezeigt) überspringt bis zu dieser Anzahl Zeichen oder bis das angegebene Zeichen gefunden wurde (welches dann auch entfernt wird). Es gibt noch den Sonderwert std::numeric_limits<std::streamsize>::max() (benötigt den Header "limits"), den man für die Anzahl der Zeichen angeben kann, der dann so viel wie "unendlich" bedeutet.

    Da ignore auch eine Art von Leseaktion ist, muss vor dem ignore natürlich erst noch ein clear erfolgen, sonst schlägt das ignore fehl.

    Bevor du aber wild Zeichen überspringst, solltest du sicher sein, dass dies auch die richtige Art der Fehlerbereinigung ist. Wenn in deinem Beispiel der Nutzer CTRL+Z gedrückt hat, dann würde ein Überspringen von Zeichen dazu führen, dass das erste Zeichen der nächsten (gewünschten!) Eingabe übersprungen würde! Denn CTRL+Z ist kein echtes Zeichen, das jemals im Eingabestrom landet. Du müsstest als unterscheiden zwischen dem Fehlerzustand eof (ausgelöst durch das CTRL+Z) und dem Fehlerzustand fail ohne eof (ausgelöst, wenn etwas nicht korrekt verarbeitet werden konnte, z.B. weil Buchstaben standen, wo Ziffern erwartet wurden). Den Fehlerstatus eines Streams kannst du mit diversen Memberfunktionen des Streams auslesen, guck z.B. hier unter "State flag functions".

    Du merkst schon, das wird kompliziert, wenn man es wirklich konsequent durchziehen möchte. Ich würde da an deiner Stelle nicht viel Zeit drauf verschwenden. Du bist sicherlich der einzige Nutzer deiner Testprogramme und kannst davon ausgehen, dass der Benutzer seine Eingaben korrekt durchführt. Und falls du dich selber mal vertippst ist es auch nicht schlimm, startest du dein Programm eben noch einmal. Die Streams sind nicht wirklich auf Nutzerinteraktion ausgelegt sondern sind wirklich nur das ganz minimale Modell einer Datenquelle. Für richtige Nutzerinteraktion würdest du ein richtiges GUI-Framework nehmen; die sind viel besser auf die Behandlung solcher Dinge ausgelegt.



  • Danke für deine Ausfühliche Erklärung! Wie du sagst verschwende ich darauf jetzt erstmal keine Energie! Vielen Dank dir!



  • Hab noch eine zweites Problem jetzt! Ich häng das einfach mal hier an um kein neues Thema aufmachen zu müssen!

    #include "std_lib_facilities.h"
    
    class Name_value {
    public:
        string name;
        int alter;
        Name_value(string na, int alt)
           :name(na), alter(alt){}
    
    };
    
    int main(){
    
    vector<Name_value> paar;
    
    string n;
    int a;
    
    while (cin >> n >> a){
    
        paar.push_back(n, a);
    
    }
    }
    

    Ist immernoch nach dem Stroustrup Buch! Diesmal will ich Eingaben wie: "Sebastian 12 Adrain 30 Emma 20 ..." in einen vetor bestehend aus Token der Klasse Name_value eingeben. Funzt aber so wie oben nicht! Kann ich das nicht direkt mit pushback in die Token lesen?

    Liebe Grüße



  • paar.push_back(Name_value(n, a));
    


  • Und wie kann ich diese Token in einer Liste dann wieder über cout ausgeben?



  • Danke hat sich erledigt!

    for(int i = 0; i < paar.size(); ++i)
    cout << paar[i].name << " " << paar[i].alter << endl;
    

  • Mod

    Ein wenig hübscher geht es durchaus

    for (auto& a : paar)
        cout << a.name << ' ' << a.alter << '\n';
    

    (Das endl war praktisch überflüssig.)



  • Arcoth schrieb:

    Ein wenig hübscher geht es durchaus

    for (auto& a : paar)
        cout << a.name << ' ' << a.alter << '\n';
    

    (Das endl war praktisch überflüssig.)

    Warum nicht

    const auto&
    

    ? Nicht kritisch, aber grundsätzlich


Log in to reply