while schleife: Abbruchbedingung gesucht für cin>>mem1



  • Funktioniert leider nicht so wie gewünscht. Die while schleife soll beended werden wenn kein Wert Integralen typs eingeben wurde. Wenn ich deinen Codeabschnitt in meinen einfüge (ich glaube das heißt implementiere) wird die darauf folgende while schleife auch abgebrochen. Ich poste dir mal den kompletten Code. Das Programm vergleicht einfach 2 Zahlenketten.

    #include <iostream>
    #include <vector>
    using namespace std;
    
    int main()
    {
        vector<int> ivec1, ivec2;
        cout << "Series of numbers for ivec1:" << endl;
        int mem1;
        while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
            ivec1.push_back(mem1);
        cout << "\nSeries of number for ivec2:" << endl;
            while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
                ivec2.push_back(mem1);
    
        int cnt=0;
        if(ivec1.size() <= ivec2.size()){
            for(size_t ix=0; ix != ivec1.size(); ++ix){
                if(ivec1[ix] == ivec2[ix])
                    ++cnt;
            }
            if(cnt == ivec1.size()){
                cout << "ivec1 is the same like ivec2 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
        else if(ivec1.size() > ivec2.size()){
            for(size_t ix=0; ix != ivec2.size(); ++ix){
                if(ivec2[ix] == ivec1[ix])
                    ++cnt;
            }
            if(cnt==ivec2.size()){
                cout << "ivec2 is the same like ivec1 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
    
        return 0;
    }
    

    Die Abbruchbedingung mit 9999 ist schlecht, aber ich brauche ja eine Abbruchbedingung.
    Der Code ist übrigens aus einer Aufgabe aus dem Cpp Primer entstanden. (Aufgabe 6.16)



  • Dein problem ist, dass im Eingabepuffer noch das "Nicht-integrale" Zeichen steht und auch nicht rausgelöscht wird.

    Sprich deine erste Schleife wird deswegen beendet, das Zeichen bleibt aber im Puffer -> das cin der nächsten Schleife guckt, sieht das Zeichen und bricht auch sofort ab (und alle weiteren Schleifen auch).

    Die Lösung: den Eingabepuffer leeren

    cin.clear();
    cin.ignore(cin.rdbuf()->in_avail());
    // wahlweise auch
    cin.ignore(std:numeric_limits<unsigned int>::max(), '\n');
    

    Immer dran denken: Eingeben lassen, Eingabe(-strom) prüfen, dann verarbeiten.
    Und im Fehlerfall alles clearen


  • Mod

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

    Macht nicht was du denkst und wird in vielen Fällen nicht funktionieren.

    C++-Standard schrieb:

    streamsize in_avail();
    Returns: If a read position is available, returns egptr() - gptr(). Otherwise returns showmanyc()

    [...]

    streamsize showmanyc();
    Returns: An estimate of the number of characters available in the sequence, or -1. If it returns a
    positive value, then successive calls to underflow() will not return traits::eof() until at least that
    number of characters have been extracted from the stream. If showmanyc() returns -1, then calls to
    underflow() or uflow() will fail.
    Default behavior: Returns zero.
    Remarks: Uses traits::eof().

    Hervorhebung durch mich.



  • Funktioniert nicht.

    while(cin >> mem1)
            ivec1.push_back(mem1);
        if (!cin.eof()){
            cerr << "Das war keine Zahl.\n";
            break;
        }
        cin.clear();
        return 0;
    }
    

    Ich muss dazu sagen, dass ich noch nie die funktion

    cin.clear
    

    ,

    !cin.eof()
    

    und

    cin.ignore(cin.rdbuf()->in_avail())
    

    benutzt habe. Ich weiß nicht was diese Funktionen explizit machen. Diese hatte ich nämlich noch nie in meinem Buch.

    cin.ignore(std:numeric_limits<unsigned int>::max(), '\n'); // fehlt da nicht ein Doppelpunkt zwischen std und numeric?
    

    Ich weiß außerdem nicht wo ich den Puffer explizit löschen soll. Bitte denkt daran das ich noch ein Anfänger bin und mit dem was ihr mir geschrieben habt noch nicht zurecht komme.



  • #include <iostream>
    #include <vector>
    #include <limits>
    using namespace std;
    
    int main()
    {
    	vector<int> ivec1, ivec2;
    	cout << "Series of numbers for ivec1:" << endl;
    
    	int mem1;
    	while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
    		ivec1.push_back(mem1);
    
    	cin.clear();
    	cin.ignore(numeric_limits<unsigned int>::max(), '\n'); // deine cin's gesetzt
    
    	cout << "\nSeries of number for ivec2:" << endl;
    	while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
    		ivec2.push_back(mem1);
    
    	int cnt=0;
    	if(ivec1.size() <= ivec2.size()){
    		for(size_t ix=0; ix != ivec1.size(); ++ix){
    			if(ivec1[ix] == ivec2[ix])
    				++cnt;
    		}
    		if(cnt == ivec1.size()){
    			cout << "ivec1 is the same like ivec2 at the beginning!" << endl;
    			return 0;
    		}
    		else
    			cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
    	}
    	else if(ivec1.size() > ivec2.size()){
    		for(size_t ix=0; ix != ivec2.size(); ++ix){
    			if(ivec2[ix] == ivec1[ix])
    				++cnt;
    		}
    		if(cnt==ivec2.size()){
    			cout << "ivec2 is the same like ivec1 at the beginning!" << endl;
    			return 0;
    		}
    		else
    			cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
    	}
    
    	return 0;
    }
    

    Ja, SeppJ, das kann sein. Ich hatte die 2 Zeilen nicht mehr im Kopf(lange nicht mehr gebraucht 🕶 ) und daher aus unserer FAQ hier abgekopiert gehabt getan.


  • Mod

    Keksman schrieb:

    Funktioniert nicht.

    Könntest du so etwas bitte ausführlicher beschreiben? Was gibst du ein, was erwartest du, was passiert stattdessen? Bei mir funktioniert das hervorragend, ich habe wohl bloß andere Vorstellungen, was passieren soll, als du.

    Wenn es um das

    wird die darauf folgende while schleife auch abgebrochen.

    geht: Klar, das hat Skym0sh0 ja auch schon erklärt, das geht mit meinem Code alleine nicht. Den habe ich dir schließlich als Lösung gegeben, bevor du gesagt hast, dass danach noch lauter andere Eingaben kommen.



  • Ok sorry. Ich versuche jetzt mal alles zu erkären:
    Als erstes soll der User Zahlen eingeben. Dies macht er wie folgt :
    [zahl] danach [enter] danach soll er die Möglichkeit haben wieder eine Zahl einzugeben um dann wieder [enter] zu drücken. Wenn der User z.B. nicht mehr als 3 Zahlen eingeben möchte soll er einfach einen nicht Integralen Wert eingeben um die aktuelle Schleife zu verlassen. In meinem Codebeispiel habe ich das nicht hinbekommen. Meine Abbruchbedingung lautet deshalb

    /*while(cin >> mem1 && */mem1 != 9999)
    

    wenn mem1 also == 9999 ist, wird die Schleife beendet. Wenn er die Schleife nun verlassen hat geht er auch direkt in die 2. Schleife für die 2. Zahlenkette.
    Skym0sh0's Code macht genau das gleiche wie mein Code. Wenn ich in seinem Code, in der ersten Eingabeaufforderung einen nicht Integralen Wert eingebe wird die 2. Schleife direkt beendet. Die Bedingung der 2. Schleife ist also false. Warum denn das??? Der Puffer wurde doch mit

    cin.clear();
        cin.ignore(numeric_limits<unsigned int>::max(), '\n'); // deine cin's gesetzt
    

    gelöscht. Somit sollte die 2. Schleife doch wieder auf Eingaben warten, tut sie aber nicht.
    Ich hoffe ich konnte euch erklären was meine Absicht ist.



  • Keksman schrieb:

    Die Bedingung der 2. Schleife ist also false. Warum denn das???

    Kann ich nicht nachvollziehen. Skym0sh0s Code macht genau das, was du eben beschrieben hast. Bau mal dein Projekt komplett neu.



  • Ich habe es neu gebuilded. Das Ergebnis bleibt gleich.
    Ich kann ja mal beschreiben was bei der Ausführung passiert:
    Konsolenfentser öffnet sich und in der ersten Zeile steht:
    Series of numbers for ivec1:
    Dann gebe ich die Zahl ein: 2
    Dann drücke ich Enter
    Dann gebe ich noch eine Zahl ein: 4
    Dann wieder Enter.
    Danach gebe ich einen Buchstaben ein: a
    Danach wieder Enter.
    Mein Konsolenfenster sieht nun so aus:

    Series of numbers for ivec1:
    1
    2
    3
    s
    
    Series of number for ivec2:
    ivec2 is the same like ivec1 at the beginning!
    
    Process returned 0 (0x0)   execution time : 4.382 s
    Press any key to continue.
    

    Ich habe Code::Blocks als IDE und den GNU Compiler der Standartmäßig bei Code::Blocks enthalten ist.



  • Du gibst 2 4 a ein und die Ausgabe ist 1 2 3 s. 😕 Ich würd das Projekt mal löschen, ein neues Projekt erstellen, und den Quellcode von Skym0sh0 dann kopieren.



  • ne sorry das war jetzt mein Fehler... als ich das geschrieben habe, habe ich einfach irgendwelche Zahlen und Buchstaben genommen die mir in den Kopf gekommen sind. War eine komplett neue Datei dann habe ich den neuen Code eingefügt.
    Bei mir funktioniert der Code von Skym0sh0 wirklich nicht. Der Compiler gibt keine Warnung aus und auch keine Fehlermeldung.



  • Hmm, kopier mal deinen aktuellen Quellcode hier rein.



  • #include <iostream>
    #include <vector>
    #include <limits>
    using namespace std;
    
    int main()
    {
        vector<int> ivec1, ivec2;
        cout << "Series of numbers for ivec1:" << endl;
    
        int mem1;
        while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
            ivec1.push_back(mem1);
    
        cin.clear();
        cin.ignore(numeric_limits<unsigned int>::max(), '\n'); // deine cin's gesetzt
        cout << "\nSeries of number for ivec2:" << endl;
        while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
            ivec2.push_back(mem1);
    
        int cnt=0;
        if(ivec1.size() <= ivec2.size()){
            for(size_t ix=0; ix != ivec1.size(); ++ix){
                if(ivec1[ix] == ivec2[ix])
                    ++cnt;
            }
            if(cnt == ivec1.size()){
                cout << "ivec1 is the same like ivec2 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
        else if(ivec1.size() > ivec2.size()){
            for(size_t ix=0; ix != ivec2.size(); ++ix){
                if(ivec2[ix] == ivec1[ix])
                    ++cnt;
            }
            if(cnt==ivec2.size()){
                cout << "ivec2 is the same like ivec1 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
    
        return 0;
    }
    

    exakt der gleiche der hier schon einmal gepostet wurde. Im Debug Ordner befindet sich eine ausfürhbare Datei(so wie es sein soll). ich hab es auf release und auf debug compiliert -> kein Erfolg. Ich hatte mal früher ein Buch c++ von a-z (ja ich weiß es ist schlecht) ... ABER in einem Kapitel wurde via while schleife eine Zahl immer wieder neu in eine Variable gespeichert. Diese wurde überschrieben wenn sich die while schleife wiederholte sprich wenn der benutzer eine neue Eingabe machte. Ich weiß dass die while Schleife die Eingabe auf eine Zahl geprüft hat. wenn es keine Zahl war dann wurde eine Fehlermeldung ausgegeben und die Schleife mit break; unterbrochen. Ich kann mich wirklich nur an Bruchstücke entsinne aber da stand meine ich etwas von if(!(cin EOF ) irgendwas. Ich weiß nicht warum das bei mir nicht funktioniert und bei dir schon.



  • Habe mal den Code getestet und hier mein Terminal ergebnis 😉

    $ clang++ test.cpp -o skymosho
    $ ./skymosho 
    Series of numbers for ivec1:
    1
    2
    3
    9999
    
    Series of number for ivec2:
    3
    2
    1
    9999
    ivec1 and ivec2 are not the same at the beginning!
    $ ./skymosho
    Series of numbers for ivec1:
    1
    2
    3
    s
    
    Series of number for ivec2:
    
    3
    2
    1
    9999
    ivec1 and ivec2 are not the same at the beginning!
    

    Ka was du da falsch machst 😉



  • 😞 😞 😞 das kann doch nicht sein.
    Ich habs jetzt auch noch mal unter der Eingabeaufforderung compiliert

    C:\Users\Krex\Desktop\_6.16forum>g++ main.cpp -o main.exe
    
    C:\Users\Krex\Desktop\_6.16forum>main.exe
    Series of numbers for ivec1:
    122
    23
    s
    
    Series of number for ivec2:
    ivec2 is the same like ivec1 at the beginning!
    
    C:\Users\Krex\Desktop\_6.16forum>
    

    Vll muss ich den compiler deinstallieren.. ? Was macht cin eigentlich wenn ich einen Buchstaben eingebe? Versucht es dann nicht das literal in einen int zu konvertieren in dem fall jetzt 97 nach dem ASCII Zeichensatzt. Oder wird die Schleife sofort übersprungen und auch nicht mehr an den Vektor ein neues Element hinzugefügt?


  • Mod

    Kann es sein, dass der Quelltext, den du übersetzt nicht aktuell ist? Das du vielleicht eine andere Kopie davon bearbeitet hast aber versehentlich die alte Version übersetzt? Mit dem Compiler selbst hat das jedenfalls ganz sicher nichts zu tun.
    Änder doch mal was offensichtliches an dem Quelltext, zum Beispiel mach mal den Grammatikfehler "same like" raus (das heißt "same as"!). Die Meldung bei der Ausgabe sollte sich dann entsprechend ändern.

    Was macht cin eigentlich wenn ich einen Buchstaben eingebe? Versucht es dann nicht das literal in einen int zu konvertieren in dem fall jetzt 97 nach dem ASCII Zeichensatzt. Oder wird die Schleife sofort übersprungen und auch nicht mehr an den Vektor ein neues Element hinzugefügt?

    Oh, hier liegen viele Missverständnisse vor:
    -cin ist eine Objektinstanz der Klasse istream, cin selber ist keine Funktion oder gar Schlüsselwort der Sprache. Es ist einfach ein globaler istream, der bei Programmstart an die Standardeingabe gekoppelt wird.
    -istream hat haufenweise Überladungen für den Operator>>. Beispielsweise eine für int. Diese Lesefunktionen versuchen gar nichts mit Gewalt um zu interpretieren, die verstehen bloß die im Standard vorgegebenen Zahlenformate. Ohne Zusatzmanipulatoren also bloß Zahlen im Dezimalformat.
    -Trifft nun diese Lesefunktion für Ganzzahlen auf einen Buchstaben, so ist dies ein Lesefehler. Das Istreamobjekt (also cin) wird in einen Fehlerzustand versetzt und der Buchstabe bleibt im Eingabestrom (genauer: der Fehlerzustand ist "fail". Zu unterscheiden beispielsweise vom Fehlerzustand "eof" der eintritt, wenn der Eingabestrom an seinem Ende* angelangt ist).
    -Solange ein Streamobjekt in einem Fehlerzustand ist, schlagen automatisch alle weiteren Lese- oder Schreiboperationen darauf fehl.
    -Entsprechend wird das Streamobjekt im Fehlerzustand in einem boolschen Kontext (if-Abfrage, oder hier: while-Bedingung) zu "false" ausgewertet.

    *: "Ende" heißt nicht "es sind gerade im Moment keine Zeichen da", sondern "Es sind keine Zeichen da und es werden auch niemals weitere kommen". Beispiele sind das Ende von Dateien (eof = end of file) oder wenn die Standardeingabe über entsprechende Steuerzeichen geschlossen wird (Linux CTRL+D, unter Windows afaik CTRL+Z).



  • Den Grammatikfehler habe ich korrigiert. Im Programm steht nun "same as" anstatt "same like". Der Compiler hat also die richtige Datei compiliert(Ging ja auch garnicht anders, weil ich ein komplett neues Projekt erstellt habe). Der Fehler bleibt trotzdem. Also habe ich Code::Blocks komplett deinstalliert und die aktuelle 12.11 Ming Version installiert. Das Ergebnis bleibt gleich.....
    Dann habe ich mir die Visual c++ 2010 Express Edition gedownloaded und installiert.
    Es hat funktioniert 😮
    Wäre jemand von euch so nett und würde den Quellcode auch auf einem MingW Compiler testen? Vielleicht handelt es sich dort um einen bug der nicht nur bei mir auftritt.
    Sorry außerdem, dass ich nicht so schnell zurückschreiben konnte und vielen Dank schonmal für die Antworten die ich schon von euch bekommen habe 😉


  • Mod

    Ist das oben wirklich absolut 100% exakt und ungekürzt der gleiche Quellcode, den du benutzt hast?

    Keksman schrieb:

    #include <iostream>
    #include <vector>
    #include <limits>
    using namespace std;
    
    int main()
    {
        vector<int> ivec1, ivec2;
        cout << "Series of numbers for ivec1:" << endl;
    
        int mem1;
        while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
            ivec1.push_back(mem1);
    
        cin.clear();
        cin.ignore(numeric_limits<unsigned int>::max(), '\n'); // deine cin's gesetzt
        cout << "\nSeries of number for ivec2:" << endl;
        while(cin >> mem1 && mem1 != 9999) // Notlösung zum abbrechen
            ivec2.push_back(mem1);
    
        int cnt=0;
        if(ivec1.size() <= ivec2.size()){
            for(size_t ix=0; ix != ivec1.size(); ++ix){
                if(ivec1[ix] == ivec2[ix])
                    ++cnt;
            }
            if(cnt == ivec1.size()){
                cout << "ivec1 is the same like ivec2 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
        else if(ivec1.size() > ivec2.size()){
            for(size_t ix=0; ix != ivec2.size(); ++ix){
                if(ivec2[ix] == ivec1[ix])
                    ++cnt;
            }
            if(cnt==ivec2.size()){
                cout << "ivec2 is the same like ivec1 at the beginning!" << endl;
                return 0;
            }
            else
                cout << "ivec1 and ivec2 are not the same at the beginning!" << endl;
        }
    
        return 0;
    }
    

    Du hast kein in_avail, fflush oder sonstiges eingebaut?

    Ganz, ganz, ganz sicher?

    Wirklich sicher? Hast du auch 3x nachgeguckt? Jeder noch so kleine Unterschied könnte die Ursache sein, weil du vielleicht gar nicht die Tragweite dieses Unterschieds erkennen kannst.

    Denn fflush und in_avail würden nämlich tatsächlich was anderes machen in VS als bei mingw, was so einiges von deinen Beobachtungen erklären würde. Wenn das jedoch wirklich dein Quellcode ist, dann: 😕 ? Eigentlich kann das gar nicht sein.



  • 😮 Er hat recht. Es funktioniert mit dem MinGW (4.6.1) wirklich nicht. Habs eben ausprobiert.

    #include <iostream>
    #include <vector>
    #include <limits>
    using namespace std;
    
    int main()
    {
        vector<int> ivec1, ivec2;
    	cout << "Series of numbers for ivec1:" << endl;
    
        int mem1;
        while(cin >> mem1 && mem1 != 9999);
    
        cin.clear();
        cin.ignore(numeric_limits<unsigned int>::max(), '\n');
    
        cout << "\nSeries of number for ivec2:" << endl;
        while(cin >> mem1 && mem1 != 9999);
    }
    

    Funktioniert nicht.

    So funktioniert es aber:

    #include <iostream>
    #include <vector>
    #include <limits>
    using namespace std;
    
    int main()
    {
        vector<int> ivec1, ivec2;
    	cout << "Series of numbers for ivec1:" << endl;
    
        int mem1;
        while(cin >> mem1 && mem1 != 9999);
    
        cin.clear();
        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
    
        cout << "\nSeries of number for ivec2:" << endl;
        while(cin >> mem1 && mem1 != 9999);
    }
    

    😃 numeric_limits<unsigned int>::max() führt wohl zu einem Überlauf ( ignore will einen signed int haben) und damit zu UB.



  • out schrieb:

    😃 numeric_limits<unsigned int>::max() führt wohl zu einem Überlauf ( ignore will einen signed int haben) und damit zu UB.

    MinGW: sizeof(unsigned int) == 4 Byte
    MinGW: sizeof(std::streamsize) == 4 Byte

    MSVC11: sizeof(unsigned int) == 4 Byte
    MSVC11: sizeof(std::streamsize) == 8 Byte

    ➡ Wie eben angesprochen. ➡ Überlauf. An das hat nun eben auch keiner gedacht. Aber ist alles doch ganz logisch. 💡


Anmelden zum Antworten