Massives Problem: Laufzeitfehler!



  • Kurze Einleitung: Neu in C++ und neu im Forum 🙂

    Ich habe folgendes Programm. Es soll aus einer CSV Datei zwei Spalten einlesen, die durch ein Semikolon getrennt sind

    FRA;EZE
    NUE;CDG
    FRA;EZE
    NUE;CDG
    AMS;MUC
    NUE;CDG
    AMS;MUC
    FRA;EZE
    NUE;CDG
    AMS;MUC
    NUE;CDG
    AMS;MUC
    FRA;EZE
    NUE;CDG
    AMS;MUC
    NUE;CDG
    AMS;MUC
    FRA;EZE
    NUE;CDG
    AMS;MUC
    

    Dazu meine Klasse:

    #ifndef MA_LEG_H
    #define MA_LEG_H
    #include <iostream>
    using namespace std;
    
    class MA_LEG
    {	private: 
    		string mOrigin;
    		string mDestination;
    
    	public:
    	// Konstruktor
    		MA_LEG() {;}
    
    	//Methoden
    		const string getmOrigin() { return mOrigin; }
    		const string getmDestination() { return mDestination; }
    
    		string setmOrigin(string mOrigin) {this->mOrigin=mOrigin;}
    		string setmDestination(string mDestination) {this->mDestination=mDestination;}
    
    		static void ImportData(string file);
    };
    #endif
    

    Und meine Funktion zum Einlesen:

    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    #include "MA_LEG.h"
    
    void MA_LEG::ImportData(string file)
    {
    //Deklaration zum Einlesen derDatei
    ifstream read;
    
    //Öffnen der Datei
    read.open (file.c_str());
    
    //Hilfsdeklaration zum Einlesen der einzelnen Zeilen
    string row;
    
    //Deklaration des vector-Objekts, welches mit leg-Daten gefüllt wird
    vector<MA_LEG> listoflegs;
    
    //Einlesen der kompletten Datei bis zur letzten Zeile 
    while(!read.eof())
    {
    //Objekterzeugung
    	MA_LEG objekt;
    
    //Einlesen einer einzelnen Zeile in row	
    	getline(read,row);
    
    //Hilfsdeklarationen zum Auffinden des Trennzeichens ';'
    	int found[2];
    	found[0]=-1;
    
    //Einlesen von Spalte 1 (Origin) als string	 
    		found[1]=row.find_first_of(';', found[1-1]+1);
    		objekt.setmOrigin(row.substr(found[1-1]+1,found[1]-found[1-1]-1));
    		cout << "|" << setw(1) << objekt.getmOrigin() << "|" ;
    
    //Einlesen von Spalte 2 (Destination) als string		
    		found[2]=row.find_first_of(';', found[2-1]+1);
    		objekt.setmDestination(row.substr(found[2-1]+1,found[2]-found[2-1]-1));
    		cout << setw(1) << objekt.getmDestination() << "|" << endl; 
    
    //Befüllung des vector-Containers mit herausgelesenen leg-Daten		
    		listoflegs.push_back(objekt);
    }
    
    //Datei schließen
    read.close();
    
    //Ausgabe der Anzahl der eingelesen leg-Objekte.
    cout << listoflegs.size();
    
    }
    

    Dazu meine main:

    #include <iostream>
    #include <string>
    #include "MA_LEG.h"
    using namespace std;
    
    int main()
    {
    //Pfad der Leg-Datei im csv - Format
    string file;
    cout << " Bitte geben Sie eine einzulesende Leg-Datei ein: " << endl;
    cout << " ";
    cin >> file;
    cout << endl;
    
    //Import der Daten mit der statischen ImportData-Methode
    MA_LEG::ImportData(file);
    
    return 0;
     }
    

    Kompiliert alles ganz wunderbar und spuckt mir auch ein bisschen was aus, nämlich die ersten 5 Zeilen. Doch dann: STATUS_ACCESS_VIOLATION usw. und er spuckt eine .core Datei mit folgendem Inhalt aus:

    [main] Einlesen 1000 (0) exception: trapped!
    [main] Einlesen 1000 (0) exception: code 0xC0000005 at 0x41E1FF
    [main] Einlesen 1000 (0) exception: ax 0x0 bx 0x0 cx 0x0 dx 0xA031EB4
    [main] Einlesen 1000 (0) exception: si 0xA033034 di 0xA033030 bp 0x247FAAC sp 0x247FAA8
    [main] Einlesen 1000 (0) exception: exception is: STATUS_ACCESS_VIOLATION
    [main] Einlesen 1000 (0) stack: Stack trace:
    [main] Einlesen 1000 (0) stack: frame 0: sp = 0x247F698, pc = 0x6100A2C3
    [main] Einlesen 1000 (0) stack: frame 1: sp = 0x247F6D4, pc = 0x7C9032A8
    [main] Einlesen 1000 (0) stack: frame 2: sp = 0x247F6F8, pc = 0x7C90327A
    [main] Einlesen 1000 (0) stack: frame 3: sp = 0x247F7A8, pc = 0x7C90E48A
    [main] Einlesen 1000 (0) stack: frame 4: sp = 0x247FAAC, pc = 0x41C530
    [main] Einlesen 1000 (0) stack: frame 5: sp = 0x247FAC0, pc = 0x41B2A4
    [main] Einlesen 1000 (0) stack: frame 6: sp = 0x247FB5C, pc = 0x41D568
    [main] Einlesen 1000 (0) stack: frame 7: sp = 0x247FB78, pc = 0x41C995
    [main] Einlesen 1000 (0) stack: frame 8: sp = 0x247FC04, pc = 0x41C912
    [main] Einlesen 1000 (0) stack: frame 9: sp = 0x247FC28, pc = 0x41F5CC
    [main] Einlesen 1000 (0) stack: frame 10: sp = 0x247FC48, pc = 0x41E57C
    [main] Einlesen 1000 (0) stack: frame 11: sp = 0x247FD08, pc = 0x41E92D
    [main] Einlesen 1000 (0) stack: frame 12: sp = 0x247FD24, pc = 0x401691
    [main] Einlesen 1000 (0) stack: frame 13: sp = 0x247FF00, pc = 0x40112F
    [main] Einlesen 1000 (0) stack: frame 14: sp = 0x247FF44, pc = 0x61004402
    [main] Einlesen 1000 (0) stack: frame 15: sp = 0x247FF88, pc = 0x61004420
    [main] Einlesen 1000 (0) stack: End of stack trace (more stack frames may be present)
    

    Irgendwie denke ich das Ganze hat einen ganz einfachen trivialen Grund. Wäre genial wenn mir einer sagen könnte was da los ist. Vielen Dank!

    Grüße
    Mathias



  • Was soll der Quark mit dem found? Zum Beispiel das hier: found[2] in Zeile 42?



  • Wie gesagt: Bin neu und bastel halt ein bisschen rum um zu lernen. 😉

    Soll ein Array mit ein paar int Einträgen sein wo ich dann die Stellen mit den Semikolons speicher.

    Irgendwo da liegt irgendwie auch der Hund begraben warum das ganze nicht funktioniert.

    Mörci!


  • Mod

    Wenn found 2 Einträge hat, von denen der erste found[0] ist, welches ist dann der letzte?



  • Unabhängig vom Quark:

    Der erste Array-Index ist 0 nicht 1.



  • Okay, es müsste

    int found[3]
    

    heißen um 3 Einträge zu haben. Nämlich found[0], found[1] und found [2]. Ändert aber nix am Fehler



  • Mathias1986 schrieb:

    Okay, es müsste

    int found[3]
    

    heißen um 3 Einträge zu haben. Nämlich found[0], found[1] und found [2]. Ändert aber nix am Fehler

    Was ist denn Deiner Meinung nach der Inhalt von z.B. found[1] und found[2] , und was meinst Du, was std::string::substr tut, wenn Du es mit diesen Inhalten fütterst?



  • Also die ersten paar Zeilen funktioniert es ja. Bis Zeile 5 liest er ein, deswegen kann das Ganze so falsch nicht sein (mir ist klar dass das alles wahrscheinlich viel zu kompliziert gemacht ist, aber das ist ja erstmal egal)

    found gibt mir in der Zeile die Stelle an, wo das Semikolon ist, was auch funktioniert in einem Test. Und substring gibt mir dann den String zwischen den Semikolons was für die ersten 5 Zeilen auch wunderbar funktioniert. Nur dann kommt dieser STATUS_ACCESS_VIOLATION Fehler bei der Ausführung der mir total rätselhaft erscheint.


  • Mod

    Mathias1986 schrieb:

    Okay, es müsste

    int found[3]
    

    heißen um 3 Einträge zu haben. Nämlich found[0], found[1] und found [2]. Ändert aber nix am Fehler

    Dann gib mal bitte ein vollständiges Beispiel an, siehe dritter Link in meiner Signatur.

    Ein weiterer Fehler ist zum Beispiel deine Einleselogik aus Prüfung, Lesen, Verarbeiten. Dadurch verarbeitest du im Fehlerfall (Dateiende) einen ungültigen Datensatz, da die Prüfung vor dem Lesefehler stattfindet.



  • Ok, ich versuchs nochmal 🙂

    Hier ist der Code:

    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class MA_LEG
    {	private: 
    		string mOrigin;
    		string mDestination;
    
    	public:
    		MA_LEG() {;}
    
    		const string getmOrigin() { return mOrigin; }
    		const string getmDestination() { return mDestination; }
    
    		string setmOrigin(string mOrigin) {this->mOrigin=mOrigin;}
    		string setmDestination(string mDestination) {this->mDestination=mDestination;}
    
    		static void ImportData(string file);
    };
    
    void MA_LEG::ImportData(string file)
    {
    ifstream read;
    read.open (file.c_str());
    string row;
    vector<MA_LEG> listoflegs;
    
    while(!read.eof())
    {
    	MA_LEG objekt;
    	getline(read,row);
    	int found[3];
    	found[0]=-1;
    
    		found[1]=row.find_first_of(';', found[1-1]+1);
    		objekt.setmOrigin(row.substr(found[1-1]+1,found[1]-found[1-1]-1));
    		cout << "|" << setw(1) << objekt.getmOrigin() << "|" ;
    
    		found[2]=row.find_first_of(';', found[2-1]+1);
    		objekt.setmDestination(row.substr(found[2-1]+1,found[2]-found[2-1]-1));
    		cout << setw(1) << objekt.getmDestination() << "|" << found[1] << found[2] << endl; 
    
    		listoflegs.push_back(objekt);
    }
    read.close();
    cout << listoflegs.size();
    }
    
    int main()
    {
    string file;
    cout << " Bitte geben Sie eine einzulesende Leg-Datei ein: " << endl;
    cout << " ";
    cin >> file;
    cout << endl;
    
    MA_LEG::ImportData(file);
    return 0;
     }
    

    Was will ich?

    Ich habe eine csv Datei mit Paaren von Strings (Städte in diesem Fall) die durch Semikolons getrennt sind
    Ich suche in found die Semikolons und trenne die strings dazwischen raus mit substr
    Diese strings speicher ich in objekten meiner Klasse ab über die set-Methode
    Jede Zeile soll ein objekt von MA_LEG sein, was ich dann in den Container listoflegs schiebe und fülle.
    Kompilierung funktioniert
    Das Ganze geht die ersten fünf Zeilen supergut, aber dann ist es vorbei mit diesem STATUS_ACCESS_VIOLATION Fehler.
    Außerdem kommt eine .exe.core Datei dazu, die mir das was ich oben schonmal gepostet habe ausspuckt

    @SeppJ: Das mit der fehlerhaften Einleselogik seh ich in meinem Code irgendwie nicht


  • Mod

    Mathias1986 schrieb:

    @SeppJ: Das mit der fehlerhaften Einleselogik seh ich in meinem Code irgendwie nicht

    Nur ganz schnell, ohne mir den Rest anzusehen:

    while (!read.eof()) // hier prüfst du, ob der Stream eof gesetzt hat. (Warum eigentlich nur eof und nicht auch alle anderen Fehler?)
    {
     // ...
     getline(read,row); // Hier liest du etwas aus dem Stream, dabei kann eof erreicht werden und das Lesen dadurch scheitern
     // ...
     // Hier verarbeitest du row, egal was beim getline passiert ist, der Lesefehler wird erst beim nächsten Durchlauf entdeckt.
     // Zuvor wird dann irgendeine Nonsenszeile verarbeitet
    }
    

    Von der Logik richtig wäre:

    while (getline(read, row))
    {
     // Hier Verarbeitung von row
    }
    

    Das ist ein ganz typisches Antipattern von Leuten, die früher C gemacht haben und nun versuchen, C mit Klassen zu machen. Der Rest deiner Dateibehandlung sieht ähnlich aus (open, close). Darf ich fragen, was dein Lehrbuch ist? Es macht keinen guten Eindruck.



  • Dirk Louis - From Zero to Hero C++



  • Mathias1986 schrieb:

    From Zero to Hero C++

    Und so ein reißerischer Titel lässt dich nicht stutzen? 😉 Normalerweise sind solche Titel, die einem große Versprechen machen (von A bis Z, in 21 Tagen, ...) das Papier nicht wert, auf dem sie gedruckt sind. Bei Dirk Louis bekommt man leider auch hin und wieder den entsprechenden Eindruck - ich hab daheim eine C/C++ Referenz von ihm, die einem zwar einen groben Überblick gibts, die man aber nicht zu wörtlich nehmen darf, weil da leider auch oft Mist rauskommt.



  • Gut zu wissen. Ich mein als Einstieg wars jetzt schon nicht schlecht,
    aber solche Details ob das jetzt gut oder schlecht ist kann ich natürlich nicht rauslesen.

    Weiß jemand warum mein Programm fehlerhaft ist? 😃



  • SeppJ schrieb:

    Das ist ein ganz typisches Antipattern von Leuten, die früher C gemacht haben und nun versuchen, C mit Klassen zu machen.

    So ein Blödsinn.


  • Mod

    Bashar schrieb:

    SeppJ schrieb:

    Das ist ein ganz typisches Antipattern von Leuten, die früher C gemacht haben und nun versuchen, C mit Klassen zu machen.

    So ein Blödsinn.

    Stimmt. Ich bin zu eingerostet in C. Korrigiere:

    Das ist ein ganz typisches Antipattern von Leuten, die früher C Pascal gemacht haben. Es taucht auch sehr oft in schlechten C (und C++) Büchern auf und ist dadurch ein deutliches Warnsignal, dass dieses Buch nicht zu benutzen ist.



  • Problem offenbar gelöst!!!

    Ich hatte bei den set-Funktion die Ausgabeformate string. Das ist natürlich quatsch, ich schreibe dort void hin und alles funktioniert. Kann jetzt im Nachhinein jemand erklären warum das so war mit dem Laufzeitfehler? Ist doch irgendwie kurios oder? Wieso hatte das so eine seltsame Auswirkung?

    Jetzt kann ich beruhigt schlafen 😉 und den Dirk Louis leg ich dann wohl doch mal beiseite.

    Bis dann und thx für die schnellen Antworten!!!


  • Mod

    Über das Ende einer Funktion mit Rückgabewert zu laufen, ohne etwas zurück zu geben, erzeugt undefiniertes Verhalten.

    Konkret wird hier wohl versucht werden, eine Kopie von einem String zu erzeugen, der gar nicht da ist. Da ein String ein komplexes Objekt ist, wegen der fehlenden Rückgabe aber bloß irgendwelcher Datenmüll da steht, scheitert dies grandios.



  • SeppJ schrieb:

    Das ist ein ganz typisches Antipattern von Leuten (...)

    Das ist ein ganz typisches Antipattern von Leuten, die iostreams über eine Referenz-Doku gelernt haben (oder mit Hilfe von Manuskripten/Büchern die von Leuten verfasst wurden, die die iostreams über eine Referenz-Doku gelernt haben etcpp.).

    Dass ein Stream implizit nach bool konvertierbar ist, ist zwar sehr praktisch, aber auch vollkommen unintuitiv.


Anmelden zum Antworten