Mehrdimensionales Array auf dem Heap zur Laufzeit
-
Hallo,
ich möchte ein Programm zum Lösen eines Labyrinthes schreiben (das Labyrinth wird über ein *.txt File übergeben). Die größe des Labyrinthes wird erst zur Laufzeit bekannt sein.
Ich habe eine Klasse "Labyrinth", hier vereinfacht dargestellt:
class Labyrinth { public: Labyrinth(); Labyrinth(unsigned short width, unsigned short height); ~Labyrinth(); const unsigned short GetWidth() const { return mywidth; }; const unsigned short GetHeight() const { return myheight; }; private: char *lab_array; // Zeiger auf das Labyrinth unsigned short mywidth; // Breite des Labyrinthes unsigned short myheight; // Höhe des Labyrinthes };Der Konstruktor:
Labyrinth::Labyrinth(unsigned short width, unsigned short height) : mywidth(width), myheight(height) { lab_array = new char[mywidth][myheight]; } Labyrinth::~Labyrinth() { delete[][] lab_array; lab_array = 0; }Allerdings spuckt mir der Compiler diese Fehlermeldungen aus:
Labyrinth.cpp|13|error C2540: Kein konstanter Ausdruck als Arraygrenze|
Labyrinth.cpp|13|error C2440: '=': 'char (*)[1]' kann nicht in 'char *' konvertiert werden|
||=== Build finished: 2 errors, 0 warnings ===|Hier also meine Fragen:
-
Kann ich überhaupt delete[][] schreiben? Der Compiler meldete dabei schon einen Fehler, aber wie kann ich dann Mehrdimensionale Arrays löschen?
-
Kann ich überhaupt auf dem Heap unter der Laufzeit des Array erstellen? Der Compiler meldet hier ja eine Fehlermeldung
-
Was kann ich gegen den 3ten Fehler machen?
-
-
Schau auch hier:
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1850524.html#1850524Im empfehle auch dir
std::vectorzu nehmen.1. Nein (wenn du die Lösung für die Frage 2 hast, erledigt sich diese Frage)
2. Ja (siehe Link)
3. Welcher dritter Fehler?
-
Probier mal
char **lab_array;.
Löschen würde ich das so:for (int i = 0; i < mywidth; i++) { delete[] lab_array[i]; } delete[] lab_array;Ungetestet und keine Ahnung ob das geht!
Gruß
-
theliquidwave schrieb:
Probier mal
char **lab_array;.
Löschen würde ich das so:for (int i = 0; i < mywidth; i++) { delete[] lab_array[i]; } delete[] lab_array;Ungetestet und keine Ahnung ob das geht!
Gruß
Ja. Das kann gehen, ist aber kaum das, was er will.
-
Danke,
ich habe es jetzt so abgeändert:
class Labyrinth { public: Labyrinth(); Labyrinth(unsigned short width, unsigned short height); const unsigned short GetWidth() const { return mywidth; }; const unsigned short GetHeight() const { return myheight; }; private: vector< vector<int> > mylab(1); unsigned short mywidth; // Breite des Labyrinthes unsigned short myheight; // Höhe des Labyrinthes }; Labyrinth::Labyrinth(unsigned short width, unsigned short height) : mywidth(width), myheight(height) { mylab.resize(mywidth); for(int i = 0; i < mywidth; ++i) { mylab[i].resize(myheight); } }Ich bekomme nun aber folgende Fehlermeldung:
d:\dokumente und einstellungen\administrator\eigene dateien\entwicklung\codeblocks\labsolver2\Labyrinth.h|15|error C2143: Syntaxfehler: Es fehlt ';' vor '<'|
d:\dokumente und einstellungen\administrator\eigene dateien\entwicklung\codeblocks\labsolver2\Labyrinth.h|15|error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht untersttzt.|
d:\dokumente und einstellungen\administrator\eigene dateien\entwicklung\codeblocks\labsolver2\Labyrinth.h|15|error C2238: Unerwartete(s) Token vor ';'|
||=== Build finished: 3 errors, 0 warnings ===|Die Fehler beziehen sich alle auf die Zeile:
vector< vector<int> > mylab(1);Was mache ich falsch? Sorry Leute, bin noch ein Anfänger und kenne mich noch nicht so gut aus.
-
Die Deklaration hier ist falsch
vector< vector<int> > mylab(1);ändere das mal in
vector< vector<int> > mylab;Du kannst hier bei der Deklaration nicht schon die Größe mit angeben.
-
Auch wenn ich den Code so abändere, erhalte ich immer noch die gleiche Fehlermeldung. Habe im Internet ein Beispielcode gefunden, ich habe nur ein wenig davon abgeändert, dort wurde auch schon zu beginn die Größe angegeben.
Muss ich um vector benutzen zu können, vorher etwas mit template angeben?
-
GoZu schrieb:
dort wurde auch schon zu beginn die Größe angegeben.
Schau mal besser nochmal nach, ob das nicht lokale vectors waren, wo die Grösse 'zu beginn' angegeben war.
-
#include <vector>schadet auch nicht.
-
Du kannst das mit folgenden drei Zeilen Code erreichen:
void resize( std::vector<std::vector<int> >& arr, unsigned int Width, unsigned int Height ) { // Schritt 1: äusseren Vektor auf Länge 1 setzen arr.resize( 1 ); // Schritt 2: inneren Vektor (1. Element) auf Länge Width setzen arr[0].resize( Width ); // Schritt 3: äusseren Vektor auf Länge Height setzen, neu hinzugefügte Elemente als Kopie des 1. Elements einfügen (haben damit die Länge Width) arr.resize( Height, arr[0] ); };
-
DocShoe schrieb:
Du kannst das mit folgenden drei Zeilen Code erreichen:
void resize( std::vector<std::vector<int> >& arr, unsigned int Width, unsigned int Height ) { // Schritt 1: äusseren Vektor auf Länge 1 setzen arr.resize( 1 ); // Schritt 2: inneren Vektor (1. Element) auf Länge Width setzen arr[0].resize( Width ); // Schritt 3: äusseren Vektor auf Länge Height setzen, neu hinzugefügte Elemente als Kopie des 1. Elements einfügen (haben damit die Länge Width) arr.resize( Height, arr[0] ); };Falls das dazu dienen soll, die Wahrscheinlichkeit des Fehlschlagens zu minimieren, ist das nicht sehr beeindruckend, ansonsten nur umständlich. Immerhin ist ein verschachtelter vector bestenfalls eine Krücke, so wie es ein nackter Doppelzeiger ist.
Neben anderen Problemen ist es zum Beispiel nicht möglich, vernünftig über alle Elemente des Arrays zu iterieren, so dass die direkte Anwendung von Standardalgorithmen ausgeschlossen ist.void resize( std::vector<std::vector<int> >& arr, unsigned int Width, unsigned int Height ) { vector<vector<int> >( Width, vector<int>( Height ) ).swap( arr ); };erscheint sinnvoller, und ist nebenbei exceptionsicher. Beide Lösungen haben den Nachteil, dass der ursprüngliche Arrayinhalt nicht bewahrt wird (ok, in der ersten Variante schon, indem die Elemente der ersten Zeile dupliziert werden, was aber eher selten das Gewünschte sein dürfte).
Erstaunlich, dass wieder nicht auf die offensichtliche Lösung hingewiesen wird:
Da C++ keine mehrdimensionalen Arrays kennt, kann statt dessen ein Array mit der gewünschten Anzahl Elemente erzeugt werden, das dann in Verbindung mit einer Abbildung, die die Koordinaten in eine einzelne Zahl wandelt, verwendet wird. Im einfachsten Fallclass Labyrinth { public: ... private: char& at(unsigned x, unsigned y); const char& at(unsigned x, unsigned y) const; vector<char> lab_array; // Zeiger auf das Labyrinth unsigned short mywidth; // Breite des Labyrinthes unsigned short myheight; // Höhe des Labyrinthes }; char& Labyrinth::at(unsigned x, unsigned y) { return lab_array[ y * mywidth + x ]; } const char& Labyrinth::at(unsigned x, unsigned y) const { return lab_array[ y * mywidth + x ]; }ein resize wird damit trivial über vectors resize realisiert.
Eleganter geht es mit boost MultiArray#include "boost/multi_array.hpp" class Labyrinth { typedef boost::multi_array_types::size_type size_type; public: Labyrinth() {} Labyrinth(size_type width, size_type height) : lab( boost::extents[width][height] ) {} size_type GetWidth() const { return lab.shape()[0]; } size_type GetHeight() const { return lab.shape()[1]; } void resize(size_type width, size_type height) { lab.resize( boost::extents[width][height] ); } char& at(size_type x, size_type y) { return lab[x][y]; } const char& at(size_type x, size_type y) const { return lab[x][y]; } private: boost::multi_array<char,2> lab; };