Dyn Mehrdimensionale Array AccessViolation



  • Guten abend nochmal. Ich möchte für meine Hamster in Labyrinth KI ein Labyrinth bauen. Das spielfeld will ich mit einem zweidimensionalen Array machen (True= wand & False = raum). Das tut aber mit zeigern nicht wirklich weswegen ich auf diese lösung gestoßen bin. Das erste beispiel habe ich dann versucht Objektorientiert umzusetzen. Das ergebniss funktioniert bis zum aufrufen des Destruktors fehlermeldungs frei, danach kommt die Meldung "AccessViolationException". Kann mir jemand sagen wieso diese kommt bzw. wie man das fixen kann? Danke 🙂

    class Ttest
    {
    private:
    	int **Feld;
    public:
    	Ttest();
    	~Ttest();
    };
    
    Ttest::Ttest()
    {
    	//Dynamisches Mehrdimensionales Array
    	Feld = new int*[10];
    	for (int i = 0;i < 10;++i) Feld[i] = new int[5];
    
    	//testweise zugreifen
    	Feld[1][2] = 3;
    }
    
    Ttest::~Ttest()
    {
        for (int j = 0; j < 10 ; j++) delete [] Feld[j];
        delete [] Feld; 
    }
    
    int main(array<System::String ^> ^args)
    {
    Ttest Bla;
    Bla.~Ttest();
    	return 0;
    }
    


  • Du darfst den Destruktor nicht eplizit aufrufen. Weil er das sowieso macht, wenn er main verlässt und dann gibt er den Speicher noch einmal frei, auf einen Bereich, der bereits frei ist.

    btw.
    Was ist den das für eine Schreibweise in main ()?!



  • soweit ich mich erinnern kann, ist
    "^"
    das pointer symbol in pascal,

    sieht interessant aus 🙂



  • Das ist C++ gemischt mit C++/CLI, garniert mit einer Prise C. Entscheide Dich bitte, gerade am Anfang, für eine Sprache.



  • LordJaxom schrieb:

    Das ist C++ gemischt mit C++/CLI, garniert mit einer Prise C. Entscheide Dich bitte, gerade am Anfang, für eine Sprache.

    Dacht ichs doch, dass das etwas essbares ist..^^



  • int main(array<System::String ^> ^args)
    

    wurde von Visualc++ express vorgegeben. Falls irgendwas an der Syntax nicht stimmmt könnte das das verbrechen von diesem Buch sein. Eigentlich steht ja C++ drauf. Da denke ich das auch c++ drin ist 😉
    Wenn das nicht so ist lasse ich mir gerne sagen was "falsch" daran sein soll.



  • Wie hat er dir vorgegeben? Was hast du für ein Projekt erzeugt?

    Und in dem Buch sehe ich das auch nirgends. (zumindest beim einlesekapitel).



  • Das hier ist die Vorgabe von CLR-KonsolenAnwendung

    // test.cpp: Hauptprojektdatei.
    
    #include "stdafx.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
        Console::WriteLine(L"Hello World");
        return 0;
    }
    

    Die andere möglichkeit wäre die Win32-Konsolenanwendung gewesen:

    int _tmain(int argc, _TCHAR* argv[])
    {
    	return 0;
    }
    


  • Also zum einen solltest Du auf sowas wirklich achten. Wenn Du ein c++-Buch (selbst ein schlechtes) hast müsste Dir auffallen, dass die main-Signatur gaaanz anders aussieht. Da sollte man sich dann zuerst erkundigen, denn es gibt das Internet, und das Visual Studio hat sogar ein Handbuch. Da wäre schnell klar gewesen, dass CLR auf eine .NET-Anwendung hinausläuft und nicht in reinem C++ geschrieben wird.

    Was dann passiert wenn man aufgrund von falschen Vorgaben per Trial&Error weitermacht, hast Du ja jetzt selbst gemerkt :).

    Also, meine Empfehlung: Mach es so, wie es im Buch steht. Und arbeite Dich in die Grundlagen ein, damit Du zumindest den syntaktischen Aufbau kennenlernst und ggfs. auch selbst erkennst, dass da etwas nicht mit rechtem C++ zugeht.

    Zurück zum Thema: Du solltest eine Win32-Konsolenanwendung (am besten ohne vorkompilierte Header, das kann man anfangs einstellen) erzeugen, und im erzeugten Quellfile das _tmain-Konstrukt einfach komplett löschen. Dann machst Du das, was im Buch steht.

    Und zum Problem: Warum rufst Du den Destruktor manuell auf? Das macht C++ am Ende der Lebenszeit des Objekts vollautomatisch.


  • Mod

    Liech schrieb:

    Die andere möglichkeit wäre die Win32-Konsolenanwendung gewesen

    Mach bei der Erstellung ein Häckchen bei "Empty Project". Anschließend fügst du im Solution Explorer manuell ein c++-file hinzu. Damit umgehst du den ganzen Unfug, dan VC++ ungefragt hinzufügt.
    Weiterhin ist es empfehlenswert, im Anschluss gleich noch Compileroptionen zu setzen:

    Unter Project/Properties:
    Configuration Properties.C/C++.General - Warning Level W4
    Configuration Properties.C/C++.Code Generation - Enable Function-Level Linking: yes (nur für DEBUG)
    Configuration Properties.C/C++.Language - Disable Language Extensions: yes

    Mit weiteren Einstellungen kann man spielen; das sind aber für den Anfang die Wichtigsten.

    Geh immer so vor, bis du irgendwann weißt, was du da machst.



  • Dankeschön für die Tipps 🙂

    Warum rufst Du den Destruktor manuell auf?
    Weil unser Info Lehrer uns ständig erzählt das ein erschaffenes Objekt wieder zerstört werden muss ohne ein wort darüber zu verlieren das es das selbst tut. Da habe ich wohl mit der Zeit das gelesene im Buch verdrängt 😉



  • Und mal wieder zurück zum Problem:

    Also du willst doch beim Dekonstruktur den Allocierten Speicher deines
    Pointer Arrays wieder löschen.
    Genau da ist dir nen Fehler unterlaufen:

    Ttest::~Ttest()
    {
        for (int j = 0; j < 10 ; j++) delete [] Feld[j];
        delete [] Feld;
    }
    

    Und zwar versuchst du ja du ja in der Schleife die Elemente von "Feld" zu löschen aber du willst aber nur die Elemente auf denen die Elemente von Feld zeigen löschen.

    Du hast ja einen DopperPointer ja wie eine art Array verwendet

    Feld[j]
    

    würde dir nur nen DoppelPointer von Feld zurückliffern und das willst du ja net
    die willst du ja nicht löschen du willst das löschen worauf diese DoppelPointer
    zeigen.Alos du musst noch einmal dereferenzieren.

    Das sieht dann mit dem Eckigen Klammer operator so aus:
    (zu gegeben dieser cast kommt mir recht spanisch vor)

    for (int j = 0; j < 10 ; j++) delete [] *(&Feld[j]);
    

    Aber in der DoppelPointer schreibweise sollte das ganze viel klarer werden

    Ttest::~Ttest()
    {   int **tmp = Feld;
        for (int j = 0; j < 10 ; j++) delete [] *(tmp++);
        delete [] Feld;
    }
    

    Bei dem Cast wird direkt auf die Zeiger Dereferenziert die auf den Speicherbereich der 5er arrays zeigen.

    Also lass dir nix erzählen mit dem Dekonstruktor hat das nix zu tun...
    aber in dem fall müsstest du ihn nicht explizit aufrufen.Aber es gibt situationen in denen das vllt auch von Praktischen nutzen ist.

    Na dann in diesem sinne 🙂



  • Dir auch ein herzliches Dankeschön 🙂


Log in to reply