multidimensionale arrays in c++



  • ^^ ausserdem nehme er besser ein eindimensionales array und berechne er sich indizes beim zugriff, anstatt mit pointer auf pointerpointer und verschachtelten allokationen herumzufummeln, ist weniger fehleranfällig.
    🙂



  • Das FAQ ist ganz interessant, hilft mit im konkreten Fall nicht weiter. Ich habe es noch mal unter Ubuntu mit Emacs versucht, wobei folgende Fehlermeldung kam:

    *** glibc detected *** ./ptr_to_arr_dyn: free(): invalid next size (fast): 0x08603038 ***
    ======= Backtrace: =========
    /lib/tls/i686/cmov/libc.so.6[0xb7c2c604]
    /lib/tls/i686/cmov/libc.so.6(cfree+0x96)[0xb7c2e5b6]
    /usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7e0f231]
    /usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xb7e0f28d]
    ./ptr_to_arr_dyn[0x80489bf]
    /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7bd3775]
    ./ptr_to_arr_dyn[0x80487a1]
    ======= Memory map: ========
    08048000-08049000 r-xp 00000000 08:01 188938 /home/ifmp09/Desktop/progs/ptr_to_arr_dyn
    08049000-0804a000 r--p 00000000 08:01 188938 /home/ifmp09/Desktop/progs/ptr_to_arr_dyn
    0804a000-0804b000 rw-p 00001000 08:01 188938 /home/ifmp09/Desktop/progs/ptr_to_arr_dyn
    08603000-08624000 rw-p 08603000 00:00 0 [heap]
    b7a00000-b7a21000 rw-p b7a00000 00:00 0
    b7a21000-b7b00000 ---p b7a21000 00:00 0
    b7b94000-b7b95000 rw-p b7b94000 00:00 0
    b7b95000-b7b99000 r-xp 00000000 08:01 205595 /usr/lib/libXdmcp.so.6.0.0
    b7b99000-b7b9a000 rw-p 00003000 08:01 205595 /usr/lib/libXdmcp.so.6.0.0
    b7b9a000-b7b9c000 r-xp 00000000 08:01 205584 /usr/lib/libXau.so.6.0.0
    b7b9c000-b7b9d000 r--p 00001000 08:01 205584 /usr/lib/libXau.so.6.0.0
    b7b9d000-b7b9e000 rw-p 00002000 08:01 205584 /usr/lib/libXau.so.6.0.0
    b7b9e000-b7b9f000 rw-p b7b9e000 00:00 0
    b7b9f000-b7ba1000 r-xp 00000000 08:01 266588 /lib/tls/i686/cmov/libdl-2.9.so
    b7ba1000-b7ba2000 r--p 00001000 08:01 266588 /lib/tls/i686/cmov/libdl-2.9.so
    b7ba2000-b7ba3000 rw-p 00002000 08:01 266588 /lib/tls/i686/cmov/libdl-2.9.so
    b7ba3000-b7bbb000 r-xp 00000000 08:01 206168 /usr/lib/libxcb.so.1.1.0
    b7bbb000-b7bbc000 r--p 00017000 08:01 206168 /usr/lib/libxcb.so.1.1.0
    b7bbc000-b7bbd000 rw-p 00018000 08:01 206168 /usr/lib/libxcb.so.1.1.0
    b7bbd000-b7d19000 r-xp 00000000 08:01 266585 /lib/tls/i686/cmov/libc-2.9.so
    b7d19000-b7d1a000 ---p 0015c000 08:01 266585 /lib/tls/i686/cmov/libc-2.9.so
    b7d1a000-b7d1c000 r--p 0015c000 08:01 266585 /lib/tls/i686/cmov/libc-2.9.so
    b7d1c000-b7d1d000 rw-p 0015e000 08:01 266585 /lib/tls/i686/cmov/libc-2.9.so
    b7d1d000-b7d20000 rw-p b7d1d000 00:00 0
    b7d20000-b7d2d000 r-xp 00000000 08:01 244865 /lib/libgcc_s.so.1
    b7d2d000-b7d2e000 r--p 0000c000 08:01 244865 /lib/libgcc_s.so.1
    b7d2e000-b7d2f000 rw-p 0000d000 08:01 244865 /lib/libgcc_s.so.1
    b7d2f000-b7d53000 r-xp 00000000 08:01 266589 /lib/tls/i686/cmov/libm-2.9.so
    b7d53000-b7d54000 r--p 00023000 08:01 266589 /lib/tls/i686/cmov/libm-2.9.so
    b7d54000-b7d55000 rw-p 00024000 08:01 266589 /lib/tls/i686/cmov/libm-2.9.so
    b7d55000-b7d56000 rw-p b7d55000 00:00 0
    b7d56000-b7e3a000 r-xp 00000000 08:01 206469 /usr/lib/libstdc++.so.6.0.10
    b7e3a000-b7e3e000 r--p 000e3000 08:01 206469 /usr/lib/libstdc++.so.6.0.10
    b7e3e000-b7e3f000 rw-p 000e7000 08:01 206469 /usr/lib/libstdc++.so.6.0.10
    b7e3f000-b7e45000 rw-p b7e3f000 00:00 0
    b7e45000-b7f2f000 r-xp 00000000 08:01 205578 /usr/lib/libX11.so.6.2.0
    b7f2f000-b7f30000 ---p 000ea000 08:01 205578 /usr/lib/libX11.so.6.2.0
    b7f30000-b7f31000 r--p 000ea000 08:01 205578 /usr/lib/libX11.so.6.2.0
    b7f31000-b7f33000 rw-p 000eb000 08:01 205578 /usr/lib/libX11.so.6.2.0
    b7f33000-b7f34000 rw-p b7f33000 00:00 0
    b7f40000-b7f44000 rw-p b7f40000 00:00 0
    b7f44000-b7f45000 r-xp b7f44000 00:00 0 [vdso]
    b7f45000-b7f61000 r-xp 00000000 08:01 293777 /lib/ld-2.9.so
    b7f61000-b7f62000 r--p 0001b000 08:01 293777 /lib/ld-2.9.so
    b7f62000-b7f63000 rw-p 0001c000 08:01 293777 /Aborted

    Es hängt natürlich mit der Speicherverwaltung zusammen. Aber ich sehe es nicht im Code. Wäre nett, wenn mir jemand die Augen öffnen würde.

    das gehört zum einen eigentlich ins standard-C++ Forum, zum anderen gibts in der dortigen FAQ einen Beitrag zum Thema multidimensionale Arrays. Vielleicht hilft dir der weiter.

    Sorry, ich bin gerade eben erst auf das Forum gestoßen.



  • Du kannst nicht davon ausgehen, dass die Zeilen und Spalten (und bei dir noch die "Tiefe") hintereinandern im Speicher liegen, da "new" irgendwo Speicher belegt. Aus diesem Grund dürfte die Zeigearithmetik, die du Anwendest (++ptr; *ptr = i;) nicht funktionieren, bzw. nur bedingt. Wenn du allerdings das Feld nicht dynamisch anforderst, sondern schon im Voraus die Größe festlegst, liegen alle Werte hintereinander im Speicher und es sollte funktionieren.

    Wenn du bei der dynamsichen Variante bleiben möchtest, brauchst du drei verschiedene Interatoren. Einen, der über die Zeilen iteriert, einen weiteren der in jeder Zeile über die Spalten interiert und noch einen weiteren, der in jeder Spalte über die "Tiefe" iteriert.

    bnz



  • Du kannst nicht davon ausgehen, dass die Zeilen und Spalten (und bei dir noch die "Tiefe") hintereinandern im Speicher liegen, da "new" irgendwo Speicher belegt. Aus diesem Grund dürfte die Zeigearithmetik, die du Anwendest (++ptr; *ptr = i;) nicht funktionieren, bzw. nur bedingt.

    Warum nur bedingt? Wieso erhalte ich dann eine korrekte Ausgabe ohne Segmentation Fault?

    Wenn du bei der dynamsichen Variante bleiben möchtest, brauchst du drei verschiedene Interatoren. Einen, der über die Zeilen iteriert, einen weiteren der in jeder Zeile über die Spalten interiert und noch einen weiteren, der in jeder Spalte über die "Tiefe" iteriert.

    Hier der Versuch:

    // pointer to array for dynamically allocated arrays
    // ptr_to_arr_dyn
    
    #include<iostream>
    int main() {
    	// input data
    	int row, column, depth;
    	std:: cout << "Enter the values for row; column, depth";
    	std:: cin >> row >> column >> depth;
    
    	// dynamic allocation
    	int ***arr = new int**[row];
    		for (int i=0; i<row; ++i) {
    			arr[i] = new int*[column];
    			for (int j=0; j<column; ++j)
    				arr[i][j] = new int[depth];
    		}
    
    	// fill in the natural numbers
    	int n=0;
    	for(int (*itrrow)[column][depth]=arr; itrrow<arr+row; ++itrrow)
    		for(int (*itrcolumn)[depth]=*itrrow; itrcolumn<*itrrow+column; ++itrcolumn)
    			for(int *itrdepth=*itrcolumn; itrdepth<*itrcolumn+depth; ++itrdepth) {
    				*itrdepth=n;
    				std::cout << *itrdepth << "\n";
    				++n;				
    	}	
    
    	// free memory	
    	for (int i=0; i<row; ++i) {
    		for (int j=0; j<column; ++j)
    			delete[] arr[i][j];
    		delete[] arr[i];
    	}
    	delete[] arr;
    	return 0;
    }
    

    Es scheitert nur lediglich noch an Zeile 21, bzw. daran, das ich nicht weiß, wie man einen Pointer mit dem ersten Element eines dynamisch allozierten multidimensionalen arrays initialisiert. Ich finde auch nichts darüber im w3. Schon mal danke für die Tipps. 🙂



  • Hallo!

    Ich hab das mal für die Schule machen müssen, also ein mehrdimensionales Array mit Pointer auf Pointer.

    Kannst ja mal schauen ob du irgendwas davon brauchst.

    #include<iostream>
    #include<conio.h>
    
    using namespace std;
    
    //Prototypen
    int** make2dFeld(int,int);
    void init2dFeld(int**,int,int);
    void out2dFeld(int**,int,int);
    void delete2dFeld(int**,int);
    
    //Definitionen
    void delete2dFeld(int** zeig,int z)
    {
        //Spalten des Feldes freigeben
        for(int i=0;i<z;i++)
        {
            delete []zeig[i];
        }
        //Zeilen(Zeigerfeld) freigeben
        delete []zeig;
        cout<<"Feld geloescht!"<<endl;
    }
    
    void out2dFeld(int** zeig,int s,int z)
    {
        cout<<"Inhalt des Feldes"<<endl<<endl;
    
        //Ausgabe des Feldes
        for(int i=0;i<z;i++)
        {
            cout<<endl;
    
            for(int j=0;j<s;j++)
            {
                cout<<zeig[i][j]<<" ";
            }
        }
        cout<<endl;
    }
    
    int** make2dFeld(int s,int z)
    {
       int** zeiger = new int*[z];
       for(int i=0;i<z;i++)
       {
          zeiger[i] = new int[s];
       }
    
        //Jedes Feldelement 0 zuweisen
        for(int i=0;i<z;i++)
        {
            for(int j=0;j<s;j++)
            {
                zeiger[i][j]=0;
            }
        }
    
        cout<<"Feld erstellt."<<endl;
    
       return zeiger;
    }
    
    void init2dFeld(int** zeig,int s,int z)
    {
       int zahl = 0;
    
        //Zeilenweise die Spalten durchlaufen
        for(int i=0;i<z;i++)
        {
            for(int j=0;j<s;j++)
            {
                zeig[i][j]=zahl;
                zahl++;
            }
        }
    
        cout<<"Feld initialisiert."<<endl;
    }
    
    //Hauptprogramm
    int main()
    {
        int** test;
    
        test = make2dFeld(10,10);
        cout<<"Feldadresse: "<<&test<<endl;
        getch();
    
        init2dFeld(test,10,10);
        getch();
    
        out2dFeld(test,10,10);
        getch();
    
        delete2dFeld(test,10);
    
        cout<<"Feldadresse: "<<&test<<endl;
    
        getch();
        return 0;
    
    }
    


  • Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung in das Forum C++ verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Warum nur bedingt? Wieso erhalte ich dann eine korrekte Ausgabe ohne Segmentation Fault?

    Bedingt, weil du den Pointer auf die erste "Tiefe" (int *ptr=arr[0][0];) setzt. Die nächste "Tiefe" (echt ein blödes Wort, hätte nicht ein 2d-Array gerreicht? 😃 ) kann sich irgendwo anders im Speicher befinden, da "new" ja den Speicher nicht hintereinander reserviert. Wenn es doch klappt, dann sollte das eigentlich Zufall bzw. wurde es ggf. vom Compiler so eingerichtet, dass es funktioniert.

    Falls ich hier Falschaussagen mache, möge mich bitte einer der Code-Gurus hier berichtigen.

    Ansosnten sieht dein neuer Code eigentlich gut aus. Ich sehe da keinen direkten Fehler...

    bnz



  • Hi, also ich hab mir jetzt deinen code mal angeschaut und wie es aussieht scheitert das ganze mMn an zeile 28:

    delete[] arr[i][j];
    

    bis dahin läuft das programm, alle pointer und arrays werden ordnungsgemäß erstellt, gefüllt und ausgegeben aber an dieser einen stelle ist irgendwie der wurm drin. Kommentier mal die zeile aus dann wird alles laufen, frag mich aber nicht warum 😕



  • Ich beziehe mich auf den allerersten post ganz oben.



  • Es hilft tatsächlich. Es ist zwar ziemlich eigenartig aber trotzdem vielen Dank.
    Wenn mir nun noch jemand erklärt, wie man einen Pointer mit dem ersten Element eines dynamisch allozierten multidimensionalen arrays initialisiert, was nämlich zum Problem in Zeile 21 des zweiten Codes wird, gebe ich Ruhe.
    Gute Nacht



  • Warum willst du das denn unbedingt mit pointern an dieser stelle machen?

    Habe nochmal über das von mir beschriebene problem nachgedacht. Der grund dafür könnte zeile 18 sein:

    int *ptr=arr[0][0];
    

    Du hast einen pointer der auf die elemente des arrays zeigt. Wenn dann die elemente gelöscht werden sollen, gibts ein problem. Das hört sich zwas spanisch an aber eine andere erklärung hab ich im moment dafür nicht. Hoffe das hilft dir nochmal weiter.



  • Jup, wenn ich *ptr entferne geht alles, es wird auch alles ordnungsgemäß gelöscht 🙂



  • Diese ganze Rumfrickelei mit Zeigern ist hochgrading fehleranfällig. In C mag man das ja vielleicht so machen, aber in C++ kann man mit relativ wenig Aufwand eine recht robuste Klasse daraus machen.

    #include <vector>
    #include <cstddef>
    #include <stdexcept>
    
    template<typename T>
    class Array2D
    {
       std::size_t    Rows_; // Anzahl Zeilen
       std::size_t    Cols_; // Anzahl Spalten
       std::vector<T> Data_; // Inhalt
    
    public:
       Array2D() : 
          Rows_( 0 ), 
          Cols_( 0 )
       {
       }
    
       Array2D( std::size_t Rows, std::size_t Cols ) :
         Rows_( Rows ),
         Cols_( Cols ),
         Data_( Rows * Cols )
       {
       }
    
       T& operator()( std::size_t Row, std::size_t Col )
       {
          if( Row < rows() && Col < cols() )
          {
             return Data_[Row * cols() + Col];
          }
          throw std::out_of_range( "Array index out of range" );
       }
    
       const T& operator()( std::size_t Row, std::size_t Col ) const
       {
          if( Row < rows() && Col < cols() )
          {
             return Data_[Row * cols() + Cols];
          }
          throw std::out_of_range( "Array index out of range" );
       }
    
       std::size_t rows() const
       {
          return Rows_;
       }
    
       std::size_t cols() const
       {
          return Cols_;
       }
    
       bool empty() const
       {
          return Data_.empty();
       }
    
       std::size_t size() const
       {
          return Data_.size();
       }
    
       void resize( std::size_t Rows, std::size_t Cols )
       {
          Data_.resize( Rows * Cols );
          Rows_ = Rows;
          Cols_ = Cols;
       }
    };
    
    int main()
    {
       // erzeuge 0x0 Array, dann auf 5x3 vergrössern
       Array2D<int> a1;
       a1.resize( 5,3 );
    
       // erzeuge 10x20 Array
       Array2D<int> a2( 10, 20 );
    }
    

    Edit:
    Mal durch den Compiler geschickt und Bugs entfernt 😃



  • @ DocShoe:

    ist zwar alles gut und schön was du sagst, aber bei mir z.B. wurden nie Vectoren dran genommen, also durften wir sowas auch nicht benutzen (wahrscheinlich weil es der Lehrer selbst nicht kann 😃 ).

    Also blieb uns nix anderes übrig als Pointer auf Pointer usw.



  • Na jut, dann will ich das mal durchgehen lassen...
    Nach wie vor ist mein Einwand gültig, durch den Zugriff auf Rohzeiger landest du schneller in undefiniertem Verhalten als du gucken kannst. Selbst wenn du eine Lösung ohne std::vector schreiben musst kannst du die Zugriffe auf die Daten soweit kapseln, dass du robusten Code erhälst.
    Wenn ihr std::vector nicht behandelt habt, dann hast du sicherlich auch noch nichts über templates gelernt, daher solltest du versuchen, eine 2D Array Klasse mit einem konkreten Datentyp zu programmieren. Den std::vector kann man durch 10 Zeilen weiteren Code ersetzen, lediglich die resize() Methode erfordert etwas mehr Aufmerksamkeit. Und du musst natürlich den Kopierkonstruktor und Zuweisungsoperator implementieren oder verbieten, aber das sind auch schon fortgeschrittene Themen.
    Probier´s einfach mal, ist nicht so schwierig. Was man Programmieren unbedingt begreifen muss, ist dass robuster und leicht wartbarer Code wichtiger ist als irgendeine schnelle Lösung, die eher schlecht als recht funktioniert. Was du dir jetzt als Programmierstil aneignest wirst du später schwer wieder los.



  • Stimmt, wir hatten keine Vectoren und dementsprechend auch keine Templates.

    Wir durften nicht mal strings benutzen, wir mussten alles schön in chars kloppen.

    BTW: ich habe die Frage gar nicht gestellt, wollte dem Threadersteller nur mal zeigen wie es gehen könnte mit Pointer auf Pointer, und hab nur auf deine Aussage geantwortet dass es evtl. sein kann, so wie bei mir, das die das gar nicht benutzen dürfen. 😉


Anmelden zum Antworten