Dynamisches Mehrdimensionales Array



  • Guten Abend zusammen,

    ich bin neu in der Community und brauche einen Tipp wie ich weiter vorgehen kann bei meinem Problem.
    In einem anderen Thread wurde zwar das Thema erklärt aber mir fehlt irgendwie ein weiters Puzzleteil 😃 😛

    Es geht mir darum wie ich mit "new" und "delete" ein dymanisches dreidimendisonales Array erstelle.
    Die Aufgabenstellung drücke ich anders aus als sie eigentlich ist, ich soll aus einer .txt lesen das Räume gibt diese haben jeweils 5 Reihen, jeder Reihe hat 5 Sitzplätze.
    Hier mein Gedankengang:

    int*** raum;
    int raumnr;
    int reihe;
    int sitzplatz;
    
    raum = new int** [raumnr];
    raum = new int* [reihe];
    
    for(int i=0; i<reihe; i++){
         for(int j=0; j<sitzplatz; j++){
    	a[i][j]= new int [sitzplatz];
         }
    }
    
    for(int i=0; i<reihe; i++){
        for(int j=0; j<fsitzplatz; j++){
    	delete[][] raum[i][j];		
        }
    }	
    
    delete[] raum;
    

    Ich hoffe das ist nicht alles falsch 😞
    Danke für eure Hilfe 😃


  • Mod

    Ziemlich falsch, wegen Zeile 7.

    Selbst wenn das korrigiert wird, hättest du lauter einzelne Arrays, auf die von einer Reihe anderer, einzelner Arrays gezeigt wird, auf die von einem anderen Array gezeigt wird. Du hättest kein kompaktes 3D-Array, wie du es möchtest und wie es viel effizienter wäre.

    Richtig:

    vector<int> mein_array(anzahl_raeume * anzahl_reihen * anzahl_spalten);
    

    + Indexberechnung.

    Noch besser:
    Wie oben, aber in einer Klasse kapseln, die die Indexberechnung übernimmt. Am besten noch so, dass man dynamisch Räume, Reihen oder Spalten hinzu fügen kann.

    Vielleicht noch besser, da die Indexberechnung entfällt:

    vector<array<array<int, 5>, 5>> mein_array(anzahl_raume);  // Oder wahrscheinlich besser: Raeume dynamisch hinzu fuegen
    

    Das geht natürlich nur dann, wenn du weißt, dass es immer 5 Reihen mit je 5 Sitzen sind.

    Wie der erste Tipp, aber wenn es unbedingt new sein muss:

    unique_pointer<int> mein_array = new int[anzahl_raeume * anzahl_reihen * anzahl_spalten];
    

    Oder besser: make_unique statt new. Ernsthaft: Wer benutzt rohe news? Wo bekommt man das im Jahr 2014 überhaupt noch beigebracht?*

    *: Rhetorische Frage.



  • Ich glaube du brächtest in Zeile 7 schon ne For Schleife. (Wenn du SeppJ´s Hinweise nicht benutzt und weiter mit new arbeiten willst) . Aber hey.. keine Garantie 🙂



  • Zeile 17 ist auch Murks, du musst delete[] für jede Verschachtelungstiefe aufrufen.



  • SeppJ schrieb:

    Selbst wenn das korrigiert wird, hättest du lauter einzelne Arrays, auf die von einer Reihe anderer, einzelner Arrays gezeigt wird, auf die von einem anderen Array gezeigt wird. Du hättest kein kompaktes 3D-Array, wie du es möchtest und wie es viel effizienter wäre.

    Naja, im allgemeinen fände hier ein "echtes" 3D-Array schon passender, weil ja wirklich jeder Raum unterschiedlich viele Reihen mit jeweils unterschiedlich vielen Sitzplätzen haben kann. Sowas wie vector<array<array<int, N>, M>> mein_array(anzahl_raume); würde ziemlich viel Platz verschwenden wenn etwa nur eine Sitzreihe besonders lang ist und alle anderen kurz.

    Würde das wenn dann so machen:

    #include <vector>
    
    struct sitzplatz { int nummer; /* Ein Sitzplatz hat eine Nummer */ };
    
    struct reihe { std::vector<sitzplatz> sitzplaetze; /* Eine Sitz-Reihe hat viele Sitzplätze */ };
    
    struct raum { std::vector<reihe> reihen; /* Ein Raum hat viele Sitz-Reihen */ };
    
    int main()
    {
    	std::vector<raum> raueme(5); // Viele Räume
    	// Initialisiere raueme ...
    	raueme[0].reihen[1].sitzplaetze[2].nummer = 3; // Erster Raum, zweite Reihe, dritter Platz bekommt die Nummer 3
    
    }
    


  • du kannst genauso vector<vector<vector<int>>> machen. Dann hast du unterschiedliche Längen. Spart dir die überflüssigen struct-Wrapper.



  • Ich find die hier nicht überflüssig sondern notwendig um auszudrücken mit was man da eigentlich arbeitet.

    Wie würdest du dein vector<vector<vector<int>>> denn nennen? Ein Bezeichner wie rooms passt hier ja nicht wirklich, warum sollte rooms[0][0] eine Sitz-Reihe sein oder rooms[0][0][0] ein Sitzplatz? Das fände ich ziemlich verwirrend zu lesen.

    Außerdem musst du es sowieso so machen wenn ein raum etwa mehr als nur eine Ansammlung an Objekten hat (zum Beispiel Fenster, Türen, etc.). In Sachen Lesbarkeit und Erweiterbarkeit finde ich das so schon besser.

    Man kann sich ja immer noch hilfs-Methoden schreiben die es einem abnehmen die Kaskade an Objekten durchzugehen:

    /* ... */
    
    struct haus { 
        std::vector<raum> raueme; 
        int &sitzplatz(int raum_nr, int sitzreihen_nr, int platz_nr) { 
            return raueme[raum_nr].reihen[sitzreihen_nr].sitzplaetze[platz_nr].nummer; 
        }
    };
    
    int main()
    {
        haus mein_haus;
        /* ... */
        mein_haus.sitzplatz(0, 1, 2) = 3; // Raum 1, Reihe 2, Platz 3
    }
    

    Zumindest sieht man so dass es um einen Sitzplatz geht.



  • Oder schlichter

    typedef int sitzplatz;
    
    typedef sitzplatz sitzreihe[5];
    
    typedef sitzreihe raum{5];
    
    typedef vector<raum> haus;
    

    //dachte, die 5x5-Räume seien so in der Aufgabe vorgegeben.



  • happystudent schrieb:

    mein_haus.sitzplatz(0, 1, 2) = 3; // Raum 1, Reihe 2, Platz 3
    

    Oder auch einfach

    mein_haus.sitzplaetze[0][1][2] = 3;
    


  • volkard schrieb:

    Oh, Typen mit Bedeutung! Ob man da was draus machen kann?

    Hm, ich bin mir gerade nicht sicher ob das Sarkasmus ist 😃

    zirkelschluss schrieb:

    Oder auch einfach

    mein_haus.sitzplaetze[0][1][2] = 3;
    

    Ja nee, dann könnte man ja auch gleich vector<vector<vector<int>>> nehmen... Warum soll ein Sitzplatz was 3-dimensionales sein? Was ist dann mein_haus.sitzplaetze[0] oder mein_haus.sitzplaetze[0][0] ?



  • happystudent schrieb:

    Ich find die hier nicht überflüssig sondern notwendig um auszudrücken mit was man da eigentlich arbeitet.

    Wie würdest du dein vector<vector<vector<int>>> denn nennen?

    typedef int sitzplatz;
    typedef vector<sitzplatz> reihe;
    typedef vector<reihe> raum;
    typedef vector<raum> haus; // = vector<vector<vector<int>>>
    


  • oenone schrieb:

    typedef int sitzplatz;
    typedef vector<sitzplatz> reihe;
    typedef vector<reihe> raum;
    typedef vector<raum> haus; // = vector<vector<vector<int>>>
    

    Das ändert doch nichts am eigentlichen Problem. Du liest den Code der irgendwo deinen ge-typedef-ten vector<vector<vector<int>>> benutzt:

    std::cout << mein_haus[0][1][2] << '\n';
    

    und dann ist erstmal rätseln angesagt, was den die Zeile jetzt überhaupt bedeuten soll. Mal ganz davon abgesehen dass das auch nicht besser wird wenn du einen Raum um einen vector für Türen/Fenster/etc. erweitern willst.

    Dagegen so:

    std::cout << mein_haus.platz_in_raum(0, 1, 2) << '\n';
    std::cout << mein_haus.tuer_in_raum(0, 2) << '\n';
    std::cout << mein_haus.fenster_in_raum(0, 1, 3).blumenkasten(2) << '\n';
    

    und schon hat man kein Problem mehr.



  • happystudent schrieb:

    oenone schrieb:

    typedef int sitzplatz;
    typedef vector<sitzplatz> reihe;
    typedef vector<reihe> raum;
    typedef vector<raum> haus; // = vector<vector<vector<int>>>
    

    Das ändert doch nichts am eigentlichen Problem. Du liest den Code der irgendwo deinen ge-typedef-ten vector<vector<vector<int>>> benutzt:

    std::cout << mein_haus[0][1][2] << '\n';
    

    und dann ist erstmal rätseln angesagt, was den die Zeile jetzt überhaupt bedeuten soll. Mal ganz davon abgesehen dass das auch nicht besser wird wenn du einen Raum um einen vector für Türen/Fenster/etc. erweitern willst.

    Dagegen so:

    std::cout << mein_haus.platz_in_raum(0, 1, 2) << '\n';
    std::cout << mein_haus.tuer_in_raum(0, 2) << '\n';
    std::cout << mein_haus.fenster_in_raum(0, 1, 3).blumenkasten(2) << '\n';
    

    und schon hat man kein Problem mehr.

    Eigentlich sinds named parameters, die das Land braucht.

    x=berechneKegelvolumen(5,6);
    

    ist nunmal kacke. Und nicht anders sieht es in jeder x-beliebigen Lib aus.

    x=berechneKegelvolumen(hoehe:=5,radius:=6);//alles wird gut//freiwillig
    

    und dann

    std::cout << mein_haus[stockwerk:=0][sitzreihe:=1][2] << '\n';
    


  • volkard schrieb:

    Eigentlich sinds named parameters, die das Land braucht.

    Das wäre cool... Hab mal recherchiert und es gibt ja tasächlich schon ein Proposal dafür 👍


  • Mod

    Du kannst dir ja auch was schreiben, das Zugriff nur so zulaesst: mein_haus.raum(5).reihe(2).sitz(4)


  • Mod

    happystudent schrieb:

    volkard schrieb:

    Eigentlich sinds named parameters, die das Land braucht.

    Das wäre cool... Hab mal recherchiert und es gibt ja tasächlich schon ein Proposal dafür 👍

    Das ist IMO unsinniger Quatsch. Wird garantiert nie bei C++ reinkommen.



  • Arcoth schrieb:

    Das ist IMO unsinniger Quatsch. Wird garantiert nie bei C++ reinkommen.

    Vermutlich.
    Nur kommts leider auch nicht in die IDEs rein, daß man beim Funktionsaufruf die Namen lesen kann (,ohne für jedes einzelne Argument mit der Maus drüber fahren zu müssen).



  • Vielen Dank für eure Tipps,

    nach einigem hin und her habe ich die Lösung für mich gefunden.
    Ich drücke mich im Code allgemein aus.
    Zum Schluss habe ich alle Werte in diesem 3D Array = 1 gesetzt.

    int a***;
    int x;
    int y;
    int z;
    
    a = new int**[x];
    
    for(int i = 0; i < x i++) {
        a[i] = new int*[y];
    
        for(int j = 0; j < y; j++) {
    	a[i][j] = new int[z];
    
    	for(int k = 0; k < z; k++) 
    	    a[i][j][k] = true;
        }
    }
    

  • Mod

    Es sollte mich eigentlich nicht kuemmern, aber irgendwie tut's schon ein bisschen weh 😞



  • Ich bin wahrlich kein Profi, aber ich hab mich lange mit 2 und 3 Stern Zeigern abgekämpft. Hey, vergiss den Code. Das geht schon aber ist echt Müll. Das kapierst sowieso in 3 Wochen nicht mehr. Die besten Lösungen wurden schon genannt.


Log in to reply