2D-Array an Konstruktor übergeben



  • Ich kriege von meinem Compiler folgende Fehlermeldung:

    1>d:\main.cpp(10): error C2664: 'CSkin::CSkin(const char **,const short **,int,int)': Konvertierung des Parameters 1 von 'const char [2][2]' in 'const char **' nicht möglich
    

    main.cpp

    #include "main.h"
    #include "Skin.h"
    
    using namespace std;
    
    const char mySkin[2][2] = {{'a', 'b'},{'c', 'd'}};
    const char myColor[2][2] = {{NULL, NULL}, {NULL,NULL}};
    
    int main(int argc, char *argv[]) {
    	CSkin newSkin(mySkin, myColor, 2, 2);
    	return 0;
    }
    

    Skin.h

    #pragma once
    
    #include "main.h"
    
    using namespace std;
    
    class CSkin
    {
    public:
    	CSkin(const char **cSkinArray, const short **wColorArray, int iWidthArray, int iHeightArray); //die Elemente aus dem Array werden in die Vektoren kopiert ===> kein Zugriff von aussen auf den Skin möglich
    	~CSkin(void);
    private:
    	int iWidth, iHeight; //höhe und breite der bitmap
    	vector<vector<char>> cSkin; //2D-array für die zeichen
    	vector<vector<short>> wColor; //2D-Array für Farben
    };
    

    Skin.cpp

    #include "Skin.h"
    
    using namespace std;
    CSkin::CSkin(const char **cSkinArray, const short **wColorArray, int iWidthArray, int iHeightArray) //cSkinArray und wColorArray müssen die gleiche Grösse haben
    {
    	vector<vector<char>>::iterator itSkin;
    	vector<vector<short>>::iterator itColor;
    	//================================================>
    	//Elemente initialisieren
    	this->iWidth = iWidthArray;
    	this->iHeight = iHeightArray;
    	//cSkinArray kopieren
    	cSkin.resize(iWidthArray);
    	itSkin = cSkin.begin();
    	for (int x=0;x<iWidthArray;x++) {
    		for (int y=0;y<iHeightArray;y++) {
    			itSkin->resize(iHeightArray);
    			itSkin->operator[](y) = cSkinArray[x][y];
    		}
    		itSkin++; //nächstes Element
    	}
    	//========>Debug ausgabe von cSkin
    #ifdef DEBUG
    	cout << "DEBUG @ CSkin(): Inhalt von cSkin" << endl;
    	for (vector<vector<char>>::iterator it1=cSkin.begin();it1!=cSkin.end();it1++) {
    		for (vector<char>::iterator it2=it1->begin();it2!=it1->end();it2++) {
    			cout << '[' << it1 - cSkin.begin() << '|' << it2 - it1->begin() << ']' << '=' << *it2 << endl;
    		}
    	}
    #endif
    	//wColorArray kopieren
    	wColor.resize(iWidthArray);
    	itColor = wColor.begin();
    	for (int x=0;x<iWidthArray;x++) {
    		for (int y=0;y<iHeightArray;y++) {
    			itColor->resize(iHeightArray);
    			itColor->operator[](y) = wColorArray[x][y];
    		}
    		itColor++; //nächstes Element
    	}  
    }
    
    CSkin::~CSkin(void)
    {
    }
    

    Falls es jemanden interessiert: Das soll eine Klasse für ein Konsolenspiel werden.

    Irgendwie verstehe ich nicht, wie ich 2-dimensionale Arrays an Funktionen übergeben kann. Das mit dem Doppelpointer scheint ja irgendwie nicht zu funktionieren... Falls ich einfach nur 2 leere Klammern angebe, will er von mir logischerweise immer die Grösse der zweiten Dimension als Konstante haben.
    Durch ein paar schön anzusehende Casts habe ich es schon geschafft das Problem zu lösen, aber so wirklich gefallen tut mir die Lösung nicht:

    itSkin->operator[](y) = *(cSkinArray+y*iHeight+x);
    

    Kann mir jemand sagen, wie man dies "professionell" löst?



  • Ok, ein Fehler ist schon mal eliminiert. Aber trotzdem funktioniert das noch nicht.

    const char myColor[2][2] = {{NULL, NULL}, {NULL,NULL}}; //falscher Datentyp gewesen
    

    Ich kriege aber immer noch die selbe Fehlermeldung 😞



  • Wenn du mySkin und myColor als Parameter übergibst, zerfallen sie in Pointer auf const char-Array.

    Der Konstruktor müsste dann so aussehen:

    CSkin(const char (*cSkinArray)[2], const short (*wColorArray)[2], int iWidthArray, int iHeightArray);
    


  • Bitte nicht C++ und C mischen, schau dir STL-Container an (nochmal). Zwei-Dimensionale Arrays kann man genauso gut mit bspw. std::vector erstellen:

    std::vector< std::vector< char > >
    

    Dann bitte auch den Link in meiner Signatur anklicken. Bitte nicht einen Haufen Code hier rein kopieren, wo nur einige Zeilen wichtig sind.



  • Bitte nicht C++ und C mischen, schau dir STL-Container an (nochmal). Zwei-Dimensionale Arrays kann man genauso gut mit bspw. std::vector erstellen:

    wtf? Die Arrays haben eine konstante Grösse und werden nicht verändert. Die 2D-Arrays enthalten eine Art Bitmap. Diese wird der Klasse CSkin übergeben, welche sie dann einliest und verändern kann. Der Witz an der Idee ist, dass ich die Bitmaps bequem in der CPP-Datei anhand der 2D-Arrays in einer zeile definieren kann. Bei Vektoren könnte ich das nicht so einfach. Afaik müsste ich jedes Element einzeln zuweisen.

    @einszweidrei
    Die Grösse der zweiten Dimension ist nicht konstant.



  • Dann nimm ein std::array . Oder kombiniere std::array und std::vector . Kreativität ist gefragt 🙂

    Außerdem geht auch mit std::vector/std::array folgendes (C++11):

    std::vector<int> a = {1, 2, 2, ...};
    

    Oder, du nutzt einen Konstruktor (nicht C++11 nötig):

    int a[] = {1, 2, 3, 5, ...};
    
    std::vector<int> myvec(a, a + sizeof(a) / sizeof(*a) );
    

    Die gezeigten Beispiele funktionieren für jeden STL-Container.



  • Joa, danke. Ich denke das war die Lösung. Ich probiere das gleich aus 🙂



  • Buchleser1.1 schrieb:

    ...

    Konvertierung des Parameters 1 von 'const char [2][2]' in 'const char **' nicht möglich
    

    ...
    Irgendwie verstehe ich nicht, wie ich 2-dimensionale Arrays an Funktionen übergeben kann. Das mit dem Doppelpointer scheint ja irgendwie nicht zu funktionieren... Falls ich einfach nur 2 leere Klammern angebe, will er von mir logischerweise immer die Grösse der zweiten Dimension als Konstante haben.

    Dann hast du nicht verstanden, wie C-Arrays funktionieren. Wie kommst du darauf, dass das mit dem Doppelzeiger funktionieren sollte?

    char a[2][3] = {{'1','2','3'},{'A','B','C'}};
    

    hat folgendes Speicherlayout:

    Adresse:     314       315       316       317       318       319
             +---------+---------+---------+---------+---------+---------+
    Inhalt:  |   '1'   |   '2'   |   '3'   |   'A'   |   'B'   |   'C'   |
             +---------+---------+---------+---------+---------+---------+
    
             | a[0][0] | a[0][1] | a[0][2] | a[1][0] | a[1][1] | a[1][2] |
    Namen:   |----------- a[0] ------------|----------- a[1] ------------|
             |---------------------------- a ----------------------------|
    

    Beachte: Hier taucht nirgens ein Zeiger im Speicher auf. Deswegen kann du hier auch nicht auf einen Zeiger zeigen. 😉 Du kannst natürlich noch ein Zeiger-Array bauen:

    char *z[2] = {a[0],a[1]};
    

    Das sieht dann so aus:

    Adresse:     320       321
             +---------+---------+
    Inhalt:  |   314   |   317   |
             +---------+---------+
    
    Namen:   |-- z[0] -|-- z[0] -|
             |-------- z --------|
    

    und das könntest du einer Funktion übergeben:

    void foo(char** zz)
    {
      assert(z[0][0] == '1');
      assert(z[1][2] == 'C');
    }
    
       ...
       foo(z);
       ...
    

    wobei der Funktionsparameter zz dann den die Adresse 320 speichern würde.

    Der springende Punkt ist: Ein Array ist kein Zeiger. Du kannst aber einen Array-Ausdruck vom Typ T[N] an einer Stelle verwenden, wo du einen Ausdruck vom Typ T* brauchst. Da wird dann automatisch die Adresse des ersten Array-Elements eingesetzt. Das klappt aber logischerweise nur auf der ersten Ebene. Beachte, dass a[b] äquivalent zu *(a+b) ist, falls a nicht von einem benutzerdefinierten Typ ist.


Anmelden zum Antworten