Letzter Buchstabe doppelt



  • Hallo,

    ich habe das folgende Programm geschrieben, um mir die Handhabung von fstream, algorithm und vector einzuprägen.
    Funktioniert auch alles super, allerding wird beim Lesen der Datei (mit .get()) der letzte Buchstabe aus der Datei doppelt ausgegeben:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <fstream>
    using namespace std;
    
    int main()
    {
        vector<char> Buchstaben;
        vector<char>::iterator it;
        char Buchstabe;
        fstream f;
    
        f.open("daten.txt", ios::out);
        f << "Text geht rein!";
        f.close();
    
        f.open("daten.txt", ios::in);
        while(!f.eof())
        {
        f.get(Buchstabe);
        Buchstaben.push_back(Buchstabe);
        cout << Buchstabe;
        }
        f.close();
    
        cout << endl;
        reverse(Buchstaben.begin(),Buchstaben.end());
        it = Buchstaben.begin();
        while(it!=Buchstaben.end())
        {
            cout << *it;
            it++;
        }
    
        char dumb;
        cin  >> dumb;
        return 0;
    }
    

    Wieso wird der Buchstabe doppelt ausgegeben? Wie verhindere ich es?

    grüße,
    🙂



  • Standardfehler, du liest in der Datei nach dem EOF noch weiter. Der Denkfehler ist, dass du glaubst, eof() würde bereits true, wenn der nächste get()-Aufruf das Dateiende erreichen würde. Das ist aber nicht so, eof() wird erst true, nachdem ein vorheriges get() durch Erreichen des Dateiendes fehlgeschlagen ist.



  • Vertausch mal Zeile 32 mit Zeile 33... o0



  • Kóyaánasqatsi schrieb:

    Vertausch mal Zeile 32 mit Zeile 33... o0

    Nicht ganz 🙄



  • Du kannst system("pause"); (oder eben groß geschrieben) verwenden.



  • lk schrieb:

    Du kannst system("pause"); (oder eben groß geschrieben) verwenden.

    Hab mir die Methode von 'dumb' angewöhnt. Find ich besser, ist aber glaube ich vom Geschmack abhängig.

    Ich have das Problem nun so 'gelöst':

    while(!f.eof())
        {
        f.get(Buchstabe);
        if(!f.eof())
        {
            Buchstaben.push_back(Buchstabe);
            cout << Buchstabe;
        }
        }
        f.close();
    

    Die Methode funktioniert, kommt mir die etwas komisch vor, da 2x "!f.eof" geprüft wird. Ist diese Methode in Ordnung, oder sollte ich das anders lösen?

    grüße,
    🙂


  • Mod

    🙂 schrieb:

    Die Methode funktioniert, kommt mir die etwas komisch vor, da 2x "!f.eof" geprüft wird. Ist diese Methode in Ordnung, oder sollte ich das anders lösen?

    Du hast richtig erkannt, dass dies nicht sehr elegant ist. Üblicherweise macht man dies so:

    while(f.get(Buchstabe))
    {
        Buchstaben.push_back(Buchstabe);
        cout << Buchstabe;
    }
    f.close();
    

    Man könnte jetzt noch was über fstreams, open, close und Gültigkeitsbereiche sagen, aber ich will dich jetzt nicht unnötig verwirren.



  • 🙂 schrieb:

    Hab mir die Methode von 'dumb' angewöhnt. Find ich besser, ist aber glaube ich vom Geschmack abhängig.

    Ist auch besser. Noch eleganter finde ich aber ein einfaches cin.get(); .



  • Man kann auch sein Programm einfach über ein kleines Batchfile starten, wo im Batchfile dann nach MyApp.exe noch ein pause drinsteht.
    Dadurch muss man seinen Code nicht mit Test-Artefakten "verunreinigen".



  • Oder einfach in der Konsole/Bash ausführen, dann sieht man das Ergebnis auch ohne irgendwelche Skripte und kann argv für Debugzwecke etc. nutzen. 🙂



  • Gibt es eine möglichkeit die Datei nur einmal zu öffnen und sowohl Daten auszugeben und einzulesen?

    f.open("daten.txt", ios::out | ios::in);
        f << "Text geht rein!";
    
        while(f.get(Buchstabe))
        {
            Buchstaben.push_back(Buchstabe);
            cout << Buchstabe;
        }
        f.close();
    

    Wird auch ausgeführt, Compiler gibt also keine Fehlermeldungen. Allerdings wird der Text nicht ausgegeben.



  • cout musst du flushen, sonst schreibt der erst wenn der Puffer voll ist ... siehe doku 🙂 std::endl; flush't implizit.



  • padreigh schrieb:

    cout musst du flushen, sonst schreibt der erst wenn der Puffer voll ist ... siehe doku 🙂 std::endl; flush't implizit.

    Danke, funktioniert nun! ( << flush) Wieso ist das nur nötig, wenn ich die Zugriffstypen mit "|" verbinde?



  • 🙂 schrieb:

    ... wenn ich die Zugriffstypen mit "|" verbinde?

    std::cout != f .. oder was meinst du?



  • padreigh schrieb:

    std::cout != f .. oder was meinst du?

    Verstehe selber meine Frage von gestern nicht mehr so recht. 🙄
    Habe mir die Doku von flush angeschaut. Allerdings verstehe ich doch nicht so recht, wie ich sie bei mir im Code anzuwenden habe. Also an f.get.

    Sobald ich "flushe" wird der Text gedruckt, richtig?
    Flushe ich dann mit:

    cout << flush;
    

    Oder mit:

    flush(f)
    

    Vorallem wo soll ich flushen?

    grüße,
    🙂



  • cout<<flush;



  • f.open("daten.txt", ios::out | ios::in);
            f << "Text geht rein!";
    
            while(f.get(Buchstabe))
            {
                cout<<flush;
                Buchstaben.push_back(Buchstabe);
                cout << Buchstabe;
            }
        f.close();
    

    Compiler meckert nicht, Text wird aber dennoch nicht ausgegeben.


  • Mod

    edit: Quatsch. Vorgeschichte des Threads nicht beachtet.

    edit2: So, Erstmal den Thread gelesen 😃 . So geht das:

    fstream f;
      char Buchstabe;
      f.open("daten.txt", ios::out);  // Lege Datei an, falls sie nicht existiert.
      f.close();                      // Denn ansonsten könnte man sie nicht zum Lesen öffnen
    
      f.open("daten.txt", ios::out | ios::in);  // Dies geht jetzt nicht mehr schief.
      f<<"Text geht raus";
      f.seekg(0);                     // Setze Lesezeiger auf den Anfang
      while(f.get(Buchstabe))
        {
          cout << Buchstabe;
        }
      f.close();
    


  • f.open("daten.txt", ios::out | ios::in);
            f << "Text geht rein!";
    
            while(f.get(Buchstabe))
            { 
                Buchstaben.push_back(Buchstabe);
                cout << Buchstabe << flush;
            }
        f.close();
    

    Versuch so 🙂



  • f.seekg(0);                     // Setze Lesezeiger auf den Anfang
    

    Ich sollte mein Cpp-Buch etwas genauer lesen... hatte aber auch nicht daran gedacht, dass der Zeiger am Ende ist. (Obwohl er das nach dem Schreiben nur sein kann).


Anmelden zum Antworten