C++: Zeichen aus Datei einlesen



  • Hallo,

    Ich habe folgenden Code. Aber ich bekommen die Fehlermeldung " Segmentation fault (core dumped)" Hat jemand ne Idee?

    #include <iostream>
    #include <vector>     
    #include "ReadFile.h"
    
    using namespace std;
    
    bool l = false, w = false, c = false;
    int lcount = 0, wcount = 0, ccount = 0, abcount = 0;
    
    int main(int argc, char *argv[]){
    
        vector<string> parms;                             //hier werden später die Kommandozeilenargumente (KA) gespeichert
        while(--argc){parms.push_back(argv[argc]);}         //Übergabe der KA an parms, von hinten nach vorne
        string filename = parms[0];                         //parms[0] ist der Dateiname der TXT, da von hinten gezählt wurde
    
        //Überprüfung ob die Parameter korrekt eingegeben worden -l, -w, -c
        for(int i=0;i<parms.size();++i){
            if(i==0){filename = parms[i];}                  // der letzte Parameter ist der Dateiname (in diesem Fall: loreipsum-utf8.txt)
            else if(parms[i]=="-l"){l = 1;}                 // es wurde ein Parameter "-l" uebergeben -> l = true
            else if(parms[i]=="-w"){w = 1;}                 //          ""            "-w"      ""    -> w = true
            else if(parms[i]=="-c"){c = 1;}                 //          ""            "-c"      ""    -> c = true
      }
    
        // Abbruchbedingung falls KA nicht korrekt sind.
        if( !l || !w || !c){ cout << "Usage: gip-wc -w -l -c filename" << endl; return 0;}
    
        //Einlesen der Datei
        ReadFile F(filename);
    
        bool absatz(false);                                 //Brauchen wir um später die Absätze von den gezählten Wörtern ab zu ziehen, da sonst jeder Absatz als Wort gezählt wird
        while(!F.eof()){                                    //Schleife zu Zählen der Zeilen (lcount), Wörter (wcount) und Zeichen (ccount)
            char zeichen = F.GetChar();                     //Aktuelles Zeichen abfragen
    
            if(F.eof()) break;                              //Abbruch am Ende der Datei
            if(zeichen){ccount++;}                          //Bei jedem Zeichen wird gezählt
            if(isspace(zeichen)){wcount++;}                 //Bei jedem Leerzeichen, oder neuen Zeile wird ein Wort gezählt
    
            if(zeichen != '\n'){absatz=0;}                  //Wenn keine neue Zeile vorliegt kommt auch kein Absatz mehr
            if(absatz){                                     //Falls aus der Vorschleife eine neue Zeile vorkam...
                if(zeichen == '\n'){abcount++; absatz=1;}   //wird jetzt geprüft ob wieder eine neue Zeile folgt und dementsprechend ein Absatz gezählt
            }
            if(zeichen == '\n'){lcount++; absatz=1;}        //Zeilen werden gezählt und ein möglicher Absatz wird eingeleitet
    
        }
    
        int ges_wcount = wcount-abcount;                    //Final wird vom Zähler der die Wörter gezählt hat, noch die Absätze abgezogen, damit die Zahl auch stimmt
    
        //Ausgabe
        cout << endl;
        cout << "Die Datei \"" << filename << "\" hat: " << endl;
        cout << "\t" << lcount << " Zeilen"<< endl;
        cout << "\t" << ges_wcount << " Woerter" << endl;
        cout << "\t" << ccount << " Zeichen"<< endl;
    
        return 0;
    }
    

    Mit folgender Header Datei:

    #include<fstream>
    #include<string>
    
    class ReadFile { 
    
    private:
      std::string filename;
      std::fstream file;
    
    public:
      ReadFile(std::string f)  {
        filename = f;
        try {
          file.open(filename.c_str(), std::fstream::in | std::ios::binary);
        }
        catch( ... ) {
          std::cout << "Datei existiert nicht!\n";   
        };
      }
    
      ~ReadFile() { file.close();}
    
      bool eof(){ return file.eof();  }
    
      char GetChar() {
        char c = file.get();
        if (!file.eof()) return c;
      }
    };
    
    //using namespace std;
    #endif /* __READFILE_H__*/
    




  • Hallo jokki58,

    Willkommen im C++-Forum.

    jokki58 schrieb:

    Ich habe folgenden Code. Aber ich bekommen die Fehlermeldung " Segmentation fault (core dumped)" Hat jemand ne Idee?

    Zwei Stellen kommen in Betracht.

    1.) Im Konstruktor von ReadFile wirfst Du eine Exception, die nirgendwo gefangen wird. Das sollte zwar keinen 'Segmentation fault' auslösen, aber ein ungewolltes Programmende. Dass die Exception geworfen wird, ist sehr wahrscheinlich, weil 'parms[0]' in Zeile 15 nicht der Dateiname, sondern der letzte Parameter ist.

    2.)

    jokki58 schrieb:

    char GetChar() {
        char c = file.get();
        if (!file.eof()) return c;
      }
    

    .. was soll das Programm machen, wenn file.eof() false liefert? Und irgendwann passiert das immer.

    Gruß
    Werner



  • Werner Salomon schrieb:

    1.) Im Konstruktor von ReadFile wirfst Du eine Exception, die nirgendwo gefangen wird. Das sollte zwar keinen 'Segmentation fault' auslösen, aber ein ungewolltes Programmende. Das die Exception geworfen wird, ist sehr wahrscheinlich, weil 'parms[0]' in Zeile 15 nicht der Dateiname, sondern der letzte Parameter ist.

    Ich würde jetzt sagen, dort wird eine Exception gefangen, die niemals geworfen wird. Deshalb wird auch nicht festgestellt, dass die Datei nicht geöffnet werden kann.



  • @manni66: 😃 Stimmt!



  • Vielen Danke. Aber ich sitz jetzt auf der Leitung. Wie kann ich den Fehler beheben sprich was muss ich am Code ändern?



  • z.B.

    class ReadFile {
    
    private:
      std::string filename;
      std::fstream file;
    
    public:
      ReadFile(std::string f)  {
        filename = f;
        file.open(filename.c_str(), std::fstream::in | std::ios::binary);
      }
    
      bool eof(){ return file.eof();  }
      bool good() { return file.good(); }
    
      char GetChar() {
        return file.get();
      }
    };
    

    und

    ReadFile F(filename);
    if(!F.good() ) {
       std::cerr << "Fehler\n";
       exit(1);
    }
    


  • und wo ist der witz darin einen ifstream so zu kapseln, wenn man ihn genausogut "pur" verwenden könnte?



  • mit dem neuen Code bekomme ich einen Fehler dass filename nicht deklariert ist.. der ist aber deklariert





  • Swordfish schrieb:

    und wo ist der witz darin einen ifstream so zu kapseln, wenn man ihn genausogut "pur" verwenden könnte?

    Nirgendwo. Der Prof/Hiwi ist zu blöd, etwas ordentliches zu schreiben.



  • jokki58 schrieb:

    Vielen Danke. Aber ich sitz jetzt auf der Leitung. Wie kann ich den Fehler beheben sprich was muss ich am Code ändern?

    dann hast Du u.U.das #include <string> vergessen oder gelöscht.

    Ich habe mir mal erlaubt, das Ganze zu überarbeiten:

    #include <iostream>
    #include <vector>    
    #include <fstream>
    
    // .. keine globalen Variablen
    
    int main(int argc, char *argv[]){
        using namespace std;
        if( argc < 2 )
            { cout << "Usage: gip-wc -w -l -c filename" << endl; return 0;} // wozu die Optionen ??
    
        const char* filename = argv[argc-1];    // reicht auch, statt std::string
        ifstream F( filename );
        if( !F.is_open() )
        {
            cout << "Fehler beim Oeffnen der Datei '" << filename << "'" << endl;
            return 0;
        }
    
        int lcount = 0, wcount = 0, ccount = 0, abcount = 0;    // lokal deklarieren
        enum Letztes_zeichen_typ { ANFANG, SPACE, NEUE_ZEILE, ABSATZ, SONSTIGES } letztes_zeichen = ANFANG;
        F >> noskipws; // Leerzeichen mit lesen
        for( char zeichen; F >> zeichen; ++ccount )
        {
            if( zeichen == '\n' )
            {
                ++lcount;   // Zeilen zählen
                if( letztes_zeichen == SONSTIGES )
                    ++wcount;   // Wort endete mit '\n'
                if( letztes_zeichen == NEUE_ZEILE )
                {
                    ++abcount;
                    letztes_zeichen = ABSATZ;   // so wird dreimal neue Zeile nicht als zwei Absätze gezählt.
                }
                else if( letztes_zeichen == SONSTIGES || letztes_zeichen == SPACE )
                    letztes_zeichen = NEUE_ZEILE;
            }
            else if( isspace( zeichen ) )
            {
                if( letztes_zeichen == SONSTIGES )
                    ++wcount;
                letztes_zeichen = SPACE;
            }
            else
            {   // sonstiges
                letztes_zeichen = SONSTIGES;
            }
        }
        // --   Nachbehandlung
        if( letztes_zeichen == SONSTIGES || letztes_zeichen == SPACE )
        {
            ++lcount;
            ++abcount;
        }
        else if( letztes_zeichen == NEUE_ZEILE )
        {
            ++abcount;
        }
    
        //Ausgabe
        cout << endl;
        cout << "Die Datei \"" << filename << "\" hat: " << endl;
        cout << "\t" << lcount << " Zeilen"<< endl;
        cout << "\t" << wcount << " Woerter" << endl;
        cout << "\t" << ccount << " Zeichen"<< endl;
        cout << "\t" << abcount << " Absaetze" << endl;
    
        return 0;
    }
    

    Gruß
    Werner



  • Danke Werner. Jetzt klappt es teilweise 😕 Ich kompilier das Programm aber dann muss ich ja " gip-wc -w -l -c filename" eingeben aber dann sagt der mir " gip-wc : command not found" woran liegt das?



  • Dein Programm liegt nicht in den Verzeichnissen der PATH Environmentvariablen.

    Auf Linux kannst du mal ./gip-wc probieren, wenn das Programm im aktuellen Verzeichnis ist.

    Welches System/Compiler/IDE nutzt du?



  • Das Programm funktioniert jetzt. Vielen Dank an alle 🙂


Log in to reply