Ständige Exception beim String splitten



  • Darfst/kannst du die boost Bibliotheken benutzen?

    In C++ Programmen benutzt man eigentlich kein malloc(), und auch new/delete für Datenobjekte sind eher selten, wenn man die STL benutzt. Dir scheint noch einiges an C++ Grundlagen zu fehlen, insbesondere die Konstruktion von Objekten bzw. Speicherverwaltung.

    Was du machen kannst ist Folgendes:

    vector<vector<string> > vData;
    
    while( getline(fHandle, LineBuffer) )
    {
       // lokales Objekt zur Aufnahme der Token der aktuellen Zeile
       vector<string> Token;
    
       // Zeile bearbeiten
       Tokenize( LineBuffer, Token );
    
       // Token in Vektor aller Token einfügen
       vData.push_back( Token );
    }
    


  • fiorn schrieb:

    Das ging mit malloc() richtig?

    malloc(sizeof(vector<vector<string>>));
    

    ?

    Nein! Damit allokierst du den Speicher für das vector-Object, aber nicht für den Inhalt. Dein Fehler liegt bei vData[VectorIndex++] , da du da auf einen Index zugreifst, der noch nicht existiert. Ein vector kann aber dynamisch wachsen.

    Mach es so:

    //...
    vData.push_back(); // Neuen (zunächst leeren) vector ans Ende von vData anhängen
    Tokenize(LineBuffer, vData.back()); // Auf letzten Eintrag (ist der gerade zugefügte leere vector) zugreifen
    //...
    
    // Oder alternativ:
    
    //...
    vector<string> vec; // Neuen leeren vector anlegen
    Tokenize(LineBuffer, vec); // vector füllen
    vData.push_back(vec); // gefüllten vector an vData anhängen
    //...
    

    Die erste Variante dürfte aber imho performanter sein, weil da das Kopieren der Vectorelemente beim push_back(vec) entfällt.


  • Administrator

    @ipsec,
    Nur gibt es keine parameterlose push_back Methode 😉
    Und ob es wirklich so viel performanter ist, würde ich nicht einfach so annehmen. Der Kompiler darf schliesslich optimieren und wenn keine Seiteneffekt entfallen, kann er auch ein paar Kopien erledigen.

    Grüssli



  • Hallo zusammen,

    Danke für eure Antworten die erste Exception ist weg. 🙂
    Jedoch will er mit das Zeugs komischerweise nicht splitten.

    Der Code sieht jetzt so aus:

    while(getline(fHandle, LineBuffer))
    	{
    		vector<string> Token;
    
    		printf("\t Line got [%s]\n",  LineBuffer.c_str());
    		Tokenize(LineBuffer, Token); // Split each line in single words
    		/**** DBG ****/
    		for(int Idx=0;Idx<5;Idx++)
    		{
    			printf("%s -> ", Token[Idx]); 
    		}
    		/** DBG END **/
    		vData.push_back(Token);
    		printf("\n\t Data successfully splitted.\n ");
    	}
    

    Ausgabe auf der Console:

    Line got [Etat;Demandes;RΘsultats;Entretien;Configuration]
    (null) -> (null) -> (null) -> (null) -> (null) ->
             Data successfully splitted.
    

    Gruss,
    fiorn



  • Dravere schrieb:

    @ipsec,
    Nur gibt es keine parameterlose push_back Methode 😉

    Ups 😃
    Mir war so, als hätte die T() als Default-Argument.



  • .. kann mir mal einer sagen, wieso keiner auf die Idee kommt, die Wörter einfach von dem ifstream einzulesen. Wenn sie mit ';' getrennt sind, geht das doch mit einfach mit

    ifstream fHandle; // Textfile Handle // der Name 'fHandle' ist hier etwas irreführend
        for( string wort; getline( fHandle, wort, ';' ); )
            tokens.push_back( wort );
    

    bleibt nur noch mit fiorn zu klären, ob die Schachtelung des vector< vector<> > an die Zeilen gebunden ist oder ob das auch ohne geht.


  • Administrator

    1. Dein printf in der Debug-For-Schleife erzeugt undefiniertes Verhalten. Genau deswegen würde ich auf printf verzichten.
    2. Deine Debug-For-Schleife geht immer über 5 Elemente. Wieso nicht sicherheitshalber gleich die Grösse des std::vector verwenden? Mehraufwand gleich 0, Sicherheit hoch 10.
    3. Zum eigentlichen Problem: Wenn du ein Semikolon an der Position x findest und danach an der Position x startest, um das nächste Semikolon zu finden, wirst du wieder die Position x zurückbekommen. Mit all deinen Suchfunktionen gehst du nie einen Schritt weiter, sondern findest immer das erste Semikolon 😉

    Grüssli


  • Administrator

    Werner_logoff schrieb:

    .. kann mir mal einer sagen, wieso keiner auf die Idee kommt, die Wörter einfach von dem ifstream einzulesen.

    Weil niemand die Dokumentation liest und viele auch von den C++ Streams ein wenig überfordert sind 😉

    Grüssli



  • Dravere schrieb:

    1. Dein printf in der Debug-For-Schleife erzeugt undefiniertes Verhalten. Genau deswegen würde ich auf printf verzichten.
    2. Deine Debug-For-Schleife geht immer über 5 Elemente. Wieso nicht sicherheitshalber gleich die Grösse des std::vector verwenden? Mehraufwand gleich 0, Sicherheit hoch 10.
    3. Zum eigentlichen Problem: Wenn du ein Semikolon an der Position x findest und danach an der Position x startest, um das nächste Semikolon zu finden, wirst du wieder die Position x zurückbekommen. Mit all deinen Suchfunktionen gehst du nie einen Schritt weiter, sondern findest immer das erste Semikolon 😉

    Grüssli

    Hm.. des Problems Ursache habe ich wohl schon gefunden.
    Die Zeile der Textdatei wird ja richtig eingelesen.
    Wenn ich dann aber in der Funktion den übergebenen Buffer auslesen will

    while (string::npos != pos || string::npos != lastPos)
        {
    		printf("INSIDE\n");
    		//printf("
    		//printf("%s\n", str.substr(lastPos, pos - lastPos));
            // Found a token, add it to the vector.
    		printf("%i, %i \n", pos, lastPos);
    		printf("%s \n", str);
    

    (unterste Zeile), wirft er mir sofort eine Exception.

    @werner
    Hmm.. Wie gehst du da das ganze Textfile durch?
    Bzw. wo werden die einzelnen vector<string> in vData gespeichert?

    Gruss


  • Administrator

    fiorn schrieb:

    (unterste Zeile), wirft er mir sofort eine Exception.

    Da dies eine C Funktion ist, kann sie keine Exception werfen, sondern dein Debugger meldet sich wahrscheinlich, weil du undefiniertes Verhalten auslöst. Das habe ich schon in Punkt 1 erwähnt und wieso deine Funktion nicht geht, steht in Punkt 3.

    Und zur Lösung von Werner:
    Du könntest schon ein wenig mehr Eigenintiative zeigen. Schau doch zumindest in der Referenz nach, was da geschieht. Man kann fast nicht mehr zu dieser Lösung sagen, sonst schreibt man gleich den ganzen Algorithmus hin.

    Grüssli



  • fiorn schrieb:

    Hmm.. Wie gehst du da das ganze Textfile durch?
    Bzw. wo werden die einzelnen vector<string> in vData gespeichert?

    Na ja - das war die Frage nach den verschachtelten Vectoren (s.o.). Aus Deinem vorhergehenden Posting schließe ich, dass das letzte Wort nicht mit ';' beendet wird und das die Anzahl der Wörter pro Datensatz fest ist (==6?) Dann geht das mit C++Standard-Einlese-Methoden zum Beispiel so:

    std::istream& getTokens( std::istream& in, std::vector< std::string >& tokens_, int n )
    {
        using namespace std;
        vector< string > tokens;
        string token;
        for( ; n > 1 && getline( in, token, ';' ); --n ) // n-1 mal 'token;' lesen
            tokens.push_back( token );
        if( getline( in, token ) ) // letzten Token am Ende der Zeile einlesen
            swap( tokens, tokens_ ); // Ok?  dann Ergebnis übenehmen
        return in;
    }
    
    int main()
    {
        using namespace std;
        vector< vector< string > > vdata;
        ifstream fHandle( "Datei.txt" );
        for( vector< string > tokens; getTokens( fHandle, tokens, 6 );  )
            vdata.push_back( tokens );
        if( fHandle.eof() )
        {
            // Ok - bis zum Dateiende gelesen
            cout << vdata.size() << " Datensaetze gelesen" << endl;
        }
    

    fiorn schrieb:

    Und zur Lösung von Werner:
    Du könntest schon ein wenig mehr Eigenintiative zeigen. Schau doch zumindest in der Referenz nach, was da geschieht. Man kann fast nicht mehr zu dieser Lösung sagen, sonst schreibt man gleich den ganzen Algorithmus hin.

    Stimmt (s.o.)


  • Administrator

    Werner_logoff schrieb:

    fiorn schrieb:

    Und zur Lösung von Werner:
    Du könntest schon ein wenig mehr Eigenintiative zeigen. Schau doch zumindest in der Referenz nach, was da geschieht. Man kann fast nicht mehr zu dieser Lösung sagen, sonst schreibt man gleich den ganzen Algorithmus hin.

    Stimmt (s.o.)

    Zwei Sachen:
    1. Du hast falsch zitiert.
    2. Das war nicht auf dich bezogen, sondern auf fiorn 😉

    Grüssli



  • Hallo zusammen

    Ich muss mich wohl schon fast entschuldigen. 😉
    Ich hätte am Anfang auf 'Dravere' hören sollen, und auch wenns nur Debug Outputs sind trotzdem 'cout' verwenden.

    Ich habe die Ausgabe von printf falsch interpretiert.
    mit cout kommen dann schon die richtigen Worte raus.
    Und die Exception kam darum weil ich hier:

    copy(vData[outerloop].begin(), vData[outerloop].end(), Titel.begin());
    

    zuerst den VektorArray "Titel" nicht vergrössert habe.

    Das Programm funktioniert jetzt schön und gut, nur habe ich nun einen wirklich SEHR komischen Fehler.

    Wenn in der Titelzeile nun nicht 1 Wort sondern mehrere Wörter stehen (im italienischen stehen bspw für einen Ausdruck 3 Wörter) schmiert mein Programm hab.

    Nun, das willkürliche daran ist folgendes:
    Das Programm läuft die Routine wo es das Textfile auswertet perfekt durch.

    // Evalute the language file
    	LoadLanguage(sLanguagePath);
    	cout << "finished" << endl;
    

    LoadLanguage(sLanguagePath) wird ohne Fehler abgeschlossen, jedoch wird die nachricht "finished" nicht mehr auf der Console ausgegeben, stattdessen erscheint die Excpetion: "The instruction at "0x785718a8" referenced memory at "0x65746e49". The memory could not be "read"."

    Ich habe ehrlich gesagt KEINE Ahnung wie es dazu kommt, dass er mir die Konsolenausgabe nicht mehr machen will.

    Gruss,
    fiorn


  • Administrator

    fiorn schrieb:

    Ich habe ehrlich gesagt KEINE Ahnung wie es dazu kommt, dass er mir die Konsolenausgabe nicht mehr machen will.

    Weisst darauf hin, dass du noch irgendwo anderes undefiniertes Verhalten auslöst. Wenn du über Speichergrenzen hinweg schreibst, schreibst du in irgendwelchen anderen Speicher in deinem Programm rein. Die Fehler davon können sich erst viel später zeigen 😉

    Grüssli



  • Aber warum nur bei einem Ausdruck der aus 3 Worten besteht?
    Ich splitte m.W. nur nach Semikolon, und nicht nach " "?


Anmelden zum Antworten