komisches verhalten meiner while schleife



  • Guten Morgen.

    Ich versteh nicht wieso bei der Eingabe von 2222 bei str
    Sich die Schleife 4 mal sinnlos wiederholt.

    Wie würdet ihr das Problem lösen? Zusätzlich wichtig ist das bei der Eingabe nur ein Zeichen in die Variable str gespeichert wird was zurzeit auch funktioniert.

    void menue_eingabe(){
            //[X1]
    
        char str[80];
        int i;
    
        while(str[0] != '1'){
        cout << "Geben Sie einen String ein: ";
        fgets(str,2,stdin);
    
        }
    
        cout << "Mal gucken ob das klappt " << str;
    }
    


  • Denk mal nach: Wenn du vier Zeichen plus Newline in die Eingabe wirfst und pro Schleifendurchlauf ein Zeichen herausholst, woran könnte es liegen, dass die Schleife sich viermal wiederholt?

    Zudem: Warum hantierst du da mit C-Strings? Das geht deutlich bequemer mit

    #include <iostream>
    #include <string>
    
    void menue_eingabe() {
      std::string str;
    
      do {
        std::cout << "Geben Sie einen String ein: ";
        std::getline(std::cin, str); // TODO: Fehlerbehandlung
      } while(str.empty() || str[0] != '1');
    
      str.resize(1); // Verkürzt auf ein Zeichen. Ist das so gemeint?
    
      std::cout << "Mal gucken ob das klappt " << str << '\n';
    }
    


  • seldon schrieb:

    Denk mal nach: Wenn du vier Zeichen plus Newline in die Eingabe wirfst und pro Schleifendurchlauf ein Zeichen herausholst, woran könnte es liegen, dass die Schleife sich viermal wiederholt?

    Zudem: Warum hantierst du da mit C-Strings? Das geht deutlich bequemer mit

    #include <iostream>
    #include <string>
    
    void menue_eingabe() {
      std::string str;
    
      do {
        std::cout << "Geben Sie einen String ein: ";
        std::getline(std::cin, str); // TODO: Fehlerbehandlung
      } while(str.empty() || str[0] != '1');
    
      str.resize(1); // Verkürzt auf ein Zeichen. Ist das so gemeint?
    
      std::cout << "Mal gucken ob das klappt " << str << '\n';
    }
    

    Ich hab gehofft das nur ein Zeichen überprüft wird.
    Lass mich raten fgets puffert immer nur ein Zeichen zu While nacheinander?? :(.
    Das passiert, wenn man schnell was googlet xD.

    Und so hab ich das leider auch nicht gemeint.
    Bei der Eingabe selber z.B

    Eingabe: eeeeeeeeeeeeeeeeeeeeeeeeeeeee
    Soll in die Variable E = "e" Nur ein Zeichen gespeichert werden.

    Für String gibt es bestimmt ein Befehl um alles ab Zeichen X zu entfernen aber ich hätte das gerne als Char, weil halt echt nur ein Zeichen gespeichert werden soll. Was will ich den da noch mit einer komfortableren String Variable rumspielen 😃



  • OK, bitte eine genaue Beschreibung, was du willst.
    Bei welcher Eingabe willst du welches Ergebnis?



  • Nathan schrieb:

    OK, bitte eine genaue Beschreibung, was du willst.
    Bei welcher Eingabe willst du welches Ergebnis?

    #include <iostream>
    using namespace std;
    
    int main(){
    
      char E;
    
      do {
        std::cout << "Geben Sie einen String ein: ";
        cin >> E; // HIER SOLL BEI DER EINGABE NUR EIN ZEICHEN GESPEICHERT WERDEN!!!!!!
        // UND FALLS JEMAND Afkjfodjsiosffij eingeben würde nur A gespeichert werden :-)
        // DAMIT NICHT IRGENDWO ANDERS DER SPEICHER ÜBERSCHRIEBEN WIRD :(
      } while(E == '1');
    
      cout << "Mal gucken ob das klappt " << E;
    
    }
    


  • Plattfuss schrieb:

    #include <iostream>
    using namespace std;
    
    int main(){
    
      char E;
    
      do {
        std::cout << "Geben Sie einen String ein: ";
        cin >> E; // HIER SOLL BEI DER EINGABE NUR EIN ZEICHEN GESPEICHERT WERDEN!!!!!!
        // UND FALLS JEMAND Afkjfodjsiosffij eingeben würde nur A gespeichert werden :-)
        // DAMIT NICHT IRGENDWO ANDERS DER SPEICHER ÜBERSCHRIEBEN WIRD :(
      } while(E == '1');
    
      cout << "Mal gucken ob das klappt " << E;
    
    }
    

    Erstmal die do-while Schleife rauskicken. Die is blöd, weil man die Bedinungen erst am Ende der Schleife sieht, und der Code immer einmal ausgeführt wird, egal was.
    Wenn du einen char willst, dann lies einmal nen char:

    char ch;
    std::cin >> ch;
    

    ganz einfach
    Ich verstehe nicht, was du letztenendes mit dem Programm machen willst, oder was es machen soll. Daher, wie schon gesagt, formuliere mal eine "Spezifikation". Du solltest das generell schon gemacht haben, vielleicht als kleines Kommentar am Anfang deines Programmes.

    LG



  • hardware schrieb:

    Plattfuss schrieb:

    #include <iostream>
    using namespace std;
    
    int main(){
    
      char E;
    
      do {
        std::cout << "Geben Sie einen String ein: ";
        cin >> E; // HIER SOLL BEI DER EINGABE NUR EIN ZEICHEN GESPEICHERT WERDEN!!!!!!
        // UND FALLS JEMAND Afkjfodjsiosffij eingeben würde nur A gespeichert werden :-)
        // DAMIT NICHT IRGENDWO ANDERS DER SPEICHER ÜBERSCHRIEBEN WIRD :(
      } while(E == '1');
    
      cout << "Mal gucken ob das klappt " << E;
    
    }
    

    Erstmal die do-while Schleife rauskicken. Die is blöd, weil man die Bedinungen erst am Ende der Schleife sieht, und der Code immer einmal ausgeführt wird, egal was.
    Wenn du einen char willst, dann lies einmal nen char:

    char ch;
    std::cin >> ch;
    

    ganz einfach
    Ich verstehe nicht, was du letztenendes mit dem Programm machen willst, oder was es machen soll. Daher, wie schon gesagt, formuliere mal eine "Spezifikation". Du solltest das generell schon gemacht haben, vielleicht als kleines Kommentar am Anfang deines Programmes.

    LG

    #include <iostream>
    using namespace std;

    #include <iostream>
    using namespace std;
    
    int main(){
    char Eingabe;
    cin >> Eingabe; // Dieses Befehl hätte ich gerne ersetzt
    cout << endl << Eingabe;
    }
    

    Es ist doch so, wenn ich bei der Variable Eingabe jetzt mehr als ein Zeichen speicher die zusätzlichen Zeichen Probleme machen könnten.
    Da der Mist ja irgendwo Speicher überschreibt und das dann Fehler verursachen könnte.

    Und genau das will ich verhindern.



  • Plattfuss schrieb:

    Es ist doch so, wenn ich bei der Variable Eingabe jetzt mehr als ein Zeichen speicher die zusätzlichen Zeichen Probleme machen könnten.
    Da der Mist ja irgendwo Speicher überschreibt und das dann Fehler verursachen könnte.

    Und genau das will ich verhindern.

    Nein.
    Die restlichen Zeichen verbleiben dann einfach im internen Puffer des Streams und kommen beim nächsten Aufruf einer Einlesefunktion dran.



  • Nathan schrieb:

    Plattfuss schrieb:

    Es ist doch so, wenn ich bei der Variable Eingabe jetzt mehr als ein Zeichen speicher die zusätzlichen Zeichen Probleme machen könnten.
    Da der Mist ja irgendwo Speicher überschreibt und das dann Fehler verursachen könnte.

    Und genau das will ich verhindern.

    Nein.
    Die restlichen Zeichen verbleiben dann einfach im internen Puffer des Streams und kommen beim nächsten Aufruf einer Einlesefunktion dran.

    Damit kommt aber leider ein neues Problem dann auf 😞
    Code:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main(){
    char Eingabe;
    string E2;
    
    cin >> Eingabe; // Dieses Befehl hätte ich gerne ersetzt
    cout << endl << Eingabe;
    cin >> E2; // diesem CIN HIER da ist das Problem
    cout << endl << E2;
    }
    

    So und damit komme, ich dann zu einem neuen Problem xD
    Wenn ich das so mache werden beim nächsten cin hier einfach die zu vielen Zeichen genommen und so getan als hätte ich enter gedrückt 😞 Das heißt ich komme nicht zur zweiten Eingabe und die Variable E2 bekommt die zu vielen Zeichen von vorhin reingedrückt :/.

    Reicht es da schon den cin stream zu leeren oder wie würdet ihr das machen?



  • Plattfuss schrieb:

    Reicht es da schon den cin stream zu leeren oder wie würdet ihr das machen?

    Ja.
    std::istream::ignore ist die passende Funktion dafür.



  • Nathan schrieb:

    Plattfuss schrieb:

    Reicht es da schon den cin stream zu leeren oder wie würdet ihr das machen?

    Ja.
    std::istream::ignore ist die passende Funktion dafür.

    Sicher das man das so schreibt?

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main(){
    char Eingabe;
    string E2;
    
    cin >> Eingabe; // Dieses Befehl hätte ich gerne ersetzt
    cout << endl << Eingabe;
    // std::istream::ignore;  beides geht nicht
    // std::istream::ignore();
    cin >> E2;
    std::cin.ignore(std::cin.rdbuf()->in_avail());
    cout << endl << E2;
    }
    


  • Plattfuss schrieb:

    Nathan schrieb:

    Plattfuss schrieb:

    Reicht es da schon den cin stream zu leeren oder wie würdet ihr das machen?

    Ja.
    std::istream::ignore ist die passende Funktion dafür.

    Sicher das man das so schreibt?

    Das ist der Name der Funktion.
    std::cin ist vom Typ std::istream und ignore ist eine Memberfunktion von std::istream. Aufruf von Memberfunktionen geschieht mit objekt.name().
    Und nutze nicht in_avail(). Das ist höchst plattformabhängig. Nutze stattdessen std::numeric_limitsstd::streamsize::max(), das ist portable (limits includen dafür).



  • Nathan schrieb:

    Plattfuss schrieb:

    Nathan schrieb:

    Plattfuss schrieb:

    Reicht es da schon den cin stream zu leeren oder wie würdet ihr das machen?

    Ja.
    std::istream::ignore ist die passende Funktion dafür.

    Sicher das man das so schreibt?

    Das ist der Name der Funktion.
    std::cin ist vom Typ std::istream und ignore ist eine Memberfunktion von std::istream. Aufruf von Memberfunktionen geschieht mit objekt.name().
    Und nutze nicht in_avail(). Das ist höchst plattformabhängig. Nutze stattdessen std::numeric_limitsstd::streamsize::max(), das ist portable (limits includen dafür).

    Während ich jetzt kreischend vom Dach springe könnte mir jemand bitte den Code posten wie man das realisiert.



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

    Übersetzung:

    std::cin.ignore(anzahl_zeichen, '\n');
    

    verwirft bis zu anzahl_zeichen Zeichen aus std::cin, hört aber auf, wenn ein '\n'-Zeichen (ein Zeilenumbruch) gefunden wird.

    std::numeric_limits<std::streamsize>::max()
    

    ist der höchste Wert, den std::streamsize annehmen kann. std::streamsize ist ein Alias für einen vorzeichenbehafteten Integertyp (d.h. üblicherweise int oder long), der von deinem Compiler bzw. der zugehörigen Standardbibliothek benutzt wird, um Längen in I/O-Operationen darzustellen.

    In diesem speziellen Zusammenhang wird dieser Wert von ignore als unendlich interpretiert, d. h.

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

    bedeutet "verwirf unendlich viele Zeichen aus std::cin, und hör damit auf, wenn du einen Zeilenumbruch findest." Dadurch wird der Rest der Zeile im Eingabepuffer verworfen.



  • Wenns dir nur um nen Zeilenumbruch geht, nimm lieber '\n'.
    Deine arme Festplatte und Geduld, wenn du irgendwann mal millionenweise Werte in ne Datei haust mit endl nach jedem.

    LG



  • hardware schrieb:

    Deine arme Festplatte und Geduld, wenn du irgendwann mal millionenweise Werte in ne Datei haust mit endl nach jedem.

    Die Festplatte stört das nicht, das ganze I/O ist mehrfach gebuffert bis auf dem Weg zur Festplatte. Aber langsam ist das natürlich, wegen den Syscalls.



  • ooh. Und ich dachte immer, wenn man flusht schreibt der das direkt drauf.
    Da sieht man wieder, man lernt nie aus!;)



  • Tut er auch, s. 27.9.1.5 (10) in C++11. Dass 27.9.1.5 (10) relevant ist, ergibt sich aus 27.7.3.7 (7), 27.6.3.2.2 (4) und 27.9.1.5 (19).

    Da muss jetzt nicht notwendigerweise eine Festplatte unter der Datei liegen (kann bspw. auch ne RAM-Disk sein), aber mehrfach gebuffert sind die Dinge höchstens durch Umstände außerhalb deines Programms. Wenn es sich um eine reguläre Datei auf einem Dateisystem auf einer Festplatte handelt, ist davon auszugehen, dass es direkt dahingeschrieben wird, mindestens ins Journal.



  • Bist du sicher dass da ein Flush() der OS Puffer vorgeschrieben ist? Bzw. dass auch vorgeschrieben ist dass das OS den Datenträger anweisen muss seine eigenen Caches zu flushen?



  • Den Festplattencache hätte ich jetzt als Teil der Festplatte aufgefasst. So weit runter spezifiziert der Standard das nicht, weil er von solchen Dingen ja auch nichts weiß. Wenn ich das richtig lese, ist es analog zu fsync gemeint.



  • fsync muss Caches mit flushen.
    (Ausgenommen natürlich die Caches sind batteriegepuffert oder sonstwie "abgesichert".)

    http://linux.die.net/man/2/fsync schrieb:

    fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even after the system crashed or was rebooted.

    Kannst du mal den Absatz zitieren den du meinst? Bin mir nämlich nicht sicher welche Revision des Standard du meinst. Aus dem was bei mir unter 27.9.1.5 (10) steht konnte ich nicht rauslesen dass hier irgendwas wirklich an die Platte geschickt werden muss.


Anmelden zum Antworten