Anfängerproblem mit zugriffsverletzung



  • Hi

    also ich bin relativ neu in C++ und übe grad ein bissl mit Dateien einlesen und DLLs. Deswegen schreib ich grad ein Programm, was mit mithilfe einer DLL verschiedene *.txt dateien auslesen soll und deren Inhalt in ein Array aus dem mainprogramm schrewiben soll. Allerding bekomme ich beim zugriff auf dieses Array immer eine zugriffsverletzung -.-'

    code vom main programm:

    code s.u.
    

    Das komplette vs 2005 projekt gibts hier:

    http://rapidshare.com/files/166358340/dummschwaetzer.zip

    MfG
    Chris



  • Array + Zugriffverletzung = Du greifst ausserhabl des gültigen Bereichs zu. Geh mal mit dem Debugger durch und schau, wo die nicht auf die Range achtest..



  • Dazu seien noch folgende Dinge angemerkt:

    • C-Structs können gefährlich sein. Bau mindestens noch einen Konstruktor ein, um für saubere Initialisierung zu sorgen.
    • Wenn du Speicher mit new oder new[] anforderst, musst du daran denken, diesen mit delete bzw. delete[] wieder freizugeben. Besonders wenn das in zwei verschiedenen Funktionen geschieht, solltest du Acht geben, dass du keine Memory Leaks erhältst.
    • Für dynamische Arrays kannst du in C++ die STL-Container, beispielsweise std::vector , verwenden. Dann wird dir auch die Speicherverwaltung abgenommen.
    • Wenn du Zeichenkettenliterale in char -Zeigern speichern willst, solltest du wenigstens const char* statt char* verwenden, damit der Bereich auch nicht geändert werden kann. Denn Schreiben in Stringliterale führt zu undefiniertem Verhalten.


  • Also ich ändere das ganze grad auf vector um. Aber ich hab nochmal ein paar fragen:

    Nexus schrieb:

    Dazu seien noch folgende Dinge angemerkt:

    • C-Structs können gefährlich sein. Bau mindestens noch einen Konstruktor ein, um für saubere Initialisierung zu sorgen.

    Wieso bauch ich bei nem Struct nen Konstruktor? (bzw ein beispiel dazu wäre gut 😉

    Nexus schrieb:

    • Wenn du Zeichenkettenliterale in char -Zeigern speichern willst, solltest du wenigstens const char* statt char* verwenden, damit der Bereich auch nicht geändert werden kann. Denn Schreiben in Stringliterale führt zu undefiniertem Verhalten.

    Auch welche Zeile bezieht sich das?



  • ChrisKringel schrieb:

    Wieso bauch ich bei nem Struct nen Konstruktor? (bzw ein beispiel dazu wäre gut 😉

    In C++ werden struct und class bis auf den Default-Zugriffsspezifizierer gleich behandelt.

    Wenn eine Klasse keine selbstdefinierten Konstruktoren hat, kann man sie per Aggregat-Initialisierungsliste initialisieren:

    Nomen Baum = {"Baum", 'm', "Bäume", 'x'};
    

    Diese Vorgehensweise ist insofern unschön, als man sie in gewissen Ausdrücken nicht verwenden kann und die skalaren Member ohne Initialisierungsliste uninitialisiert bleiben.

    Beim Konstruktor hat man viel mehr Möglichkeiten. Man kann einen Standardkonstruktor, einen Konstruktor für 3 Argumente, einen Kopierkonstruktor etc. einrichten. So stellt man auch eine Initialisierung des Objekts sicher.

    Beispiel:

    Nomen Baum;                            // Standardkonstruktor
    Nomen Baum("Baum", 'm', "Bäume", 'y'); // Spezifischer Konstruktor
    

    ChrisKringel schrieb:

    Auch welche Zeile bezieht sich das?

    Du kennst deinen Code aber schlecht... 26 und 27.

    ChrisKringel schrieb:

    PluralGeschlecht

    Fällt dir nichts auf?



  • So also ich hab jetzt mal ein bissl geändert:

    main programm:

    #include "stdafx.h"
    
    using namespace std;
    
    int main()
    {
    	vector<Nomen> nomenContainer; //das müsste doch der Konstruktor sein oder :confused: 
    	vector<Verb> verbContainer;
    
    	int nomen = 0;
    	int verben = 0;
    
    	initDB(&nomenContainer, &verbContainer, &nomen, &verben);
    
    	system("pause");
    	return 0;
    }
    

    dll:

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    using namespace std;
    
    #define DLL extern "C" __declspec(dllexport)
    
    struct Nomen
    {
    	string Singular;
    	char SingularGeschlecht;
    	string Plural;
    	char PluralGeschlecht;
    };
    
    struct Verb
    {
    	string ich;
    	string du;
    	string erSieEs;
    	string wir;
    	string ihr;
    	string sie;
    };
    
    const char *dateiNomen = "C:\\Users\\Christian\\Documents\\Visual Studio 2005\\Projects\\Dummschwätzer\\debug\\nomen.txt";
    const char *dateiVerben = "C:\\Users\\Christian\\Documents\\Visual Studio 2005\\Projects\\Dummschwätzer\\debug\\verb.txt";
    
    void initialisiereNomen(vector<Nomen> *nomen)
    {
    	ifstream file(dateiNomen);
    
    	//cout<<"Lese Nomen ein..."<<endl;
    
    	if(file)
    	{
    		string line;
    		int position = 1;
    		int i = 0;
    
    		cout<<nomen->capacity()<<endl;//gibt die korrekte größe aus
    
    		while(getline(file, line))
    		{
    			if(line == "/startnext")
    			{
    				continue;
    			}
    
    			try
    			{
    				switch(position)
    				{
    					case 1:
    						nomen->at(i).Singular = line;
    						position++;
    						break;
    					case 2:
    						nomen->at(i).SingularGeschlecht = reinterpret_cast<char>(line.c_str());
    						position++;
    						break;
    					case 3:
    						nomen->at(i).Plural = line;
    						position++;
    						break;
    					case 4:
    						nomen->at(i).PluralGeschlecht = reinterpret_cast<char>(line.c_str());
    						position = 1;
    						i++;
    						break;
    				}
    			}catch(out_of_range exception){
    				cout<<exception.what()<<endl;
    			}
    
    		}
    
    		file.close();
    	}else{
    		cout<<"Kann Datei "<<dateiNomen<<" nicht öffnen"<<endl;
    	}
    }
    
    int zaehleObjekte(const char *fileName)
    {
    	int i = 0;
    	ifstream file(fileName);
    
    	//cout<<"pr\x81 \bfe "<<fileName<<endl<<endl;
    
    	if(file)
    	{
    		string line;
    
    		while(getline(file, line))
    		{
    			if(line == "/startnext")
    			{
    				//cout<<"neue sequenz gefunden"<<endl;
    				i++;
    			}
    		}
    
    		file.close();
    	}else{
    		cout<<"Kann Datei "<<fileName<<" nicht öffnen"<<endl;
    	}
    	//cout<<"Abgeschlossen, "<<i<<" Sequenzen gefunden"<<endl<<endl<<endl;;
    	return i;
    }
    
    DLL void initDB(vector<Nomen> *nomenContainer,vector<Verb> *verbContainer, int *anzahlNomen, int *anzahlVerben) 
    {
    	cout<<"datenbank wird initialisiert..."<<endl;
    
    	*anzahlNomen = zaehleObjekte(dateiNomen);
    
    	*anzahlVerben = zaehleObjekte(dateiVerben);
    
    	nomenContainer->reserve(*anzahlNomen);
    
    	verbContainer->reserve(*anzahlVerben);
    
    	cout<<"Kapazitaet nomenContainer: "<<nomenContainer->capacity()<<endl;
    
    	initialisiereNomen(&*nomenContainer); //<- stimmt das so?
    
    	cout<<"initialisierung abgeschlossen"<<endl;
    }
    

    Das Programm wird soweit fehlerfrei Kompiliert, allerdings kommt immernoch die zugriffsverletzung... Ich bin da mit meinen bescheidenen c++ kentnissen echt langsam überfragt ^^

    Hier noch die ausgabe vom Debugger:

    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    Eine Ausnahme (erste Chance) bei 0x767442eb in Dummschwätzer.exe: Microsoft C++-Ausnahme: std::out_of_range an Speicherposition 0x0012f898..
    

    MfG
    Chris



  • nein, hier ist der Konstruktor - oder eben auch doch eher nicht ^^

    struct Nomen 
    {
    //Nomen (...)
        string Singular; 
        char SingularGeschlecht; 
        string Plural; 
        char PluralGeschlecht; 
    }; 
    
    struct Verb 
    { 
    //Verb (...)
        string ich; 
        string du; 
        string erSieEs; 
        string wir; 
        string ihr; 
        string sie; 
    };
    
    const char *dateiVerben = "C:\\Users\\Christian\\Documents\\Visual Studio 2005\\Projects\\Dummschwätzer\\debug\\verb.txt";
    

    1. nimm statt "\" lieber "/" - dann würde es auch unter unix gehen und windows-kompatibel ist es eh - außerdem ists übersichtlicher...
    2. du musst nur den relativen pfad angeben... so kannst du die dlls samt (sammt? kA ^^) txt-dateien auch mal verschieben...

    }catch(out_of_range exception){
    
    // besser:
    catch(const out_of_range &exception)
    

    (und wenn du dir mal deine schleife anguckst, siehst du auch, dass du zwar die länge hättest, sie aber nicht nutzt... du lässt es einfach immer weiter gucken, ob was kommt - at() schmeißt dann (logischerweise) ne exception, wenn das element nicht im container vorhanden ist...)

    was genau willst du hier machen:

    reinterpret_cast<char>(line.c_str());
    

    überdenk vll besser die Funktionen noch mal...
    und vor allem deine variablen(-typen)...

    char SingularGeschlecht;
    

    such mal nach "enum"...

    auch könnte man so was besser machen:

    struct Verb
    {
        string ich;
        string du;
        string erSieEs;
        string wir;
        string ihr;
        string sie;
    };
    

    wie wärs, wenn du worte aufteilst? in die, die "normal" gebeugt werden:

    enum person //doofer name, aber naja ^^
    {
     ICH,
     DU,
     ER,
        SIE_EZ = ER, //gefällt mir auch nicht, aber sollst ja auch noch was zu tun haben - und wenns nur ist, dass du dir hübschere variablen-namen nimmst ^^
        ES = ER,
     WIR,
     IHR,
     SIE_MZ
    }
    
    std::string GetGebeugtesVerb(const std::string& wortstamm, person pers)
    {
     switch (pers)
      {
       case ICH:
        return wortstamm + "e";
       //..
      }
    }
    
    struct NormalVerb
    {
    public:
    NormalVerb(const std::string &_wortstamm) : wortstamm(_wortstamm) {}
    std::string GetWort(person pers) {return GetGebeugtesVerb(wortstamm, pers);}
    private:
    const std::string wortstamm;
    };
    

    wäre eigtl auch nen prima beispiel für polymorphie(die hässliche fkt als virtual in ne basisklasse packen etc) - aber das ist vll ein wenig hoch...

    bb



  • Würde mich trotzdem noch interessieren, was mit "PluralGeschlecht" gemeint ist. 😉



  • gut dann werd ich die dll aml neu schriben und ein bissl umstrukturieren, das dort nicht die ganze db initilaisiert wird sondern dass nur die "teilfunktione" in ihr sind...

    Nexus schrieb:

    Würde mich trotzdem noch interessieren, was mit "PluralGeschlecht" gemeint ist. 😉

    ja das is etwas undsinnig merk ich grad^^

    danke für eure hilfe 🙂 Ich glaub ich werd mich hier bald wieder melden xD


Anmelden zum Antworten