Mehrdimensionale Arrays; dynamischer Speicher;



  • Hallo Leute,

    ich soll eine Klasse implementieren, die ein (MxN)-Matrix modelliert. Die Matrixelemente sollen im dynamischen Speicher abgelegt werden.

    Das UML-Klassendiagramm, den Konstruktor und manche Methoden konnte ich implementieren. Ich scheitere momentan an dieser Methode :

    bool setElementAt(int m,int n,double value)
    

    Setzt das Matrixelement an der angegebenen Zeile und Spalte auf einen neuen Wert.
    (Dazu soll ich die Methode

    getArrayIndex(int m, int n)
    

    benutzen).

    Ich bekomme andauernd folgende Fehlermeldung :

    -extended initializer only available...
    -invalid types...

    Zu den Attributen der Klasse:

    int m_rows, m_cols, m_size;
    double* m_pArray;
    

    //Konstruktor :

    CMatrix::CMatrix(int M, int N)
    {
       if(M && N ==0) 
       {
         m_rows =2; m_cols=2;
       }
       else 
         m_rows = M; m_cols=N; m_size = m_rows*m_cols;
    
         m_pArray = new double [m_size];
    

    //Destruktor:

    CMatrix::~Matrix()
    delete [] m_pArray;
    

    //getArrayIndex

    int CMatrix::getArrayIndex(int m ,int n)
    {
       double i=0;
       if(//zusicherungen)
       {
         i=(m-1)*n+n-1; return i;
       }
       else if(//zusicherungen)
       {
         return -1;
       } 
        return 0;
    

    //setElementAt

    bool CMatrix::setElementAt(int m, int n, double value)
    {
        double index = getArrayIndex(m,n);
        if(//zusicherung)
        {
           return false;
        }
        else
           m_pArray[index] = {value}; return true; //Fehler
    

    Ich hoffe ich konnte mein Problem gut schildern 😕 falls noch fragen sind, kann ich vllt ein Bild hochladen oder so :S..Vielen Dank schonmal !



  • In deiner getArrayIndex warum ist i von Typ double? Du gibst ein int zurück.
    Bei setElementAt index ist ein double aber getArrayIndex gibt ein int zurück.
    "m_pArray[index]" index ist vom Typ double.
    Solltes auf das Problem jetzt selber kommen 😃



  • 🙄 ups xD

    okay ich hab jetzt folgendes:

    int index = getArrayIndex(m,n);
    

    jetzt wird

    m_pArray[index]={value};
    

    gelbfarbig,
    der Compiler schreibt :

    - warning: extended initalizer lists only available with -std=c++0x or -std=gnu++0x[enabled by default]

    liegt es daran das

    index
    

    variabel ist?

    Ich danke dir schonmal sehr 🙂



  • Also hier sind ein paar komische Sachen im Code

    if(M && N ==0)
    

    Du willst sicher ausdrücken "Wenn M und N null sind":

    if(M == 0 && N == 0)
    

    Per impliziter Konvertierung von int nach bool funktioniert das sicher, was ist aber, wenn du auf einen anderen Wert prüfen willst? Dann geht das nicht mehr. Besser immer richtig schreiben.

    Aber: Warum prüftst du überhaupt auf 0 und gibst den Variablen Standardwerte? Warum nicht gleich Default-Parameter und eine Exception bei m<=0 && n<=0?

    CMatrix::~Matrix()
    delete [] m_pArray;
    

    Bei Schleifen und if kannst du zwar die geschweiften Klammern weglassen, aber bei Funktionen geht das nicht.

    Anonymous123 hat ja schon einen Fehler geschrieben:

    double i=0;
    

    Deine Daten sind zwar doubles, der Index aber nicht. Ein sinnvoller Datentype wäre beispielsweise std::size_t. Den musst du dann auch als Rückgabetyp von getArrayIndex angeben.

    Während dem Schreiben ist noch eine Antwort reingekommen:

    m_pArray[index]={value};
    

    Wieso hast du die geschweiften Klammern? Mach die weg, dann sollte es klappen



  • Okay, stimmt statt

    if(M && N ==0)
    

    kann/sollte ich schreiben:

    if (m<=0 && n<=0)
    

    Laut dem UML-Klassendiagramm wird m_rows und m_cols mit 2 initialisiert.
    Ich dachte, dass ich das im Konstruktor definieren muss.

    Oh, tut mir leid, in Wirklichkeit gibt es diese Klammer :S.

    Ich habe leider nicht so einen großen Spielraum.
    Das ist eine Aufgabe von der Uni und ich muss mich an das Klassendiagramm halten :/. size_t kenne ich noch gar nicht, für was steht dieser Datentyp?

    Mh, irgendwie dachte ich die gehören dahin, hast recht ohne die Klammern funktionierts 🙂

    Ich schau mal ob noch weitere Probleme auftreten, ich muss das Projekt eh heute noch fertigstellen, also bitte den Thread nicht schließen.

    Vielen Dank für Eure hilfe 🙂



  • ...



  • CMatrix(int M = 2, int N = 2)
    

    Wenn nichts angegeben, sollen M und N 2 sein. (Beachte: Kein CMatrix:: davor, das muss nämlich in die Klassendefinition)



  • Okay, hab ich so übernommen patrick246 😉

    Ich saß noch bis spät Abends an meinem Programm.
    Bei meinem Programm stimmt nur ne Kleinigkeit noch nicht.

    In der main habe ich folgende Schleife :

    int M, N;
    	M = 4; N = 3;
    	matrix.getDimension(M,N);
    	int m =1;
    	int v =0;
    
    	for(int n=1; m<=M ;n++)
    	{
    		matrix.setElementAt(m,n,v);
    		abs(v);
    		v++;
    
    		if (v % 2 != 0) {v = v *-1;}
    
    		if(n==N)
    		{
    			n = 0; m++;
    		}
    
    	}
    

    Eigentlich soll ich ein Matrix-Feld von :

    0 -1 2
    -3 4 -5
    6 -7 8
    -9 10 -11

    aufbauen. Raus kommt jedoch :

    0 -1 0
    -1 -1 -1
    0 -1 0
    -1 0 -1

    und ich weiß einfach nicht wieso 😕

    An setElementAt hat sich nichts verändert 😞

    Ich Danke euch für Eure Hilfe 😕



  • 1. Was macht getDimension? Dem Namen nach sollte sie die Dimensionen der Matrix zurückgeben, stattdessen nimmt sie Werte entgegen.

    2. Eine NxM-Matrix kannst du mit folgender Schleife durchlaufen, angenommen die erste Position ist (0|0) und die letzte Position ist (N-1|M-1):

    int counter = 0;
    for(int n = 0; n < N; ++n)
    {
        for(int m = 0; m < M; ++m)
        {
            if((counter % 2) == 0)
                matrix.setElementAt(n, m, counter);
            else
                matrix.setElementAt(n, m, -counter);
        }
    }
    

    3. getArrayIndex

    std::size_t getArrayIndex(std::size_t y, std::size_t x)
    {
        return y * m_breite + x;
    }
    

    4. setElementAt

    void setElementAt(std::size_t y, std::size_t x, double value)
    {
        m_data[getArrayIndex(y,x)] = value;
    }
    

    Stimmen die letzten beiden ungefähr mit deinem Code überein?



  • Quadknick schrieb:

    CMatrix::CMatrix(int M, int N)
    {
       if(M && N ==0) 
       {
         m_rows =2; m_cols=2;
       }
       else 
         m_rows = M; m_cols=N; m_size = m_rows*m_cols;
    
         m_pArray = new double [m_size];
    

    der else Zweig sieht auch sehr ungesund aus



  • int CMatrix::getArrayIndex(int m ,int n)
    {
       double i=0;
       if(//zusicherungen)
       {
         i=(m-1)*n+n-1; return i; // <====== *n muss *m_cols heissen!
       }
       else if(//zusicherungen)
       {
         return -1;
       } 
        return 0;
    

    Und 1-basierte Indexe sind selten ne gute Idee.



  • Hey Leute,

    ich war am Dienstag im Labor und da haben wir den Fehler schnell gefunden.
    Hustbaer du hast recht! n muss m_cols heissen.

    Desweiteren habe ich die main-Schleife folgendermassen umprogrammiert :

    int z=1; int v=0; int M,N; M=4, N =3;
    matrix.getDimension(M,N);
    for(int m=1; m<M; m++)
    {
       for(int n=1;n<=N;n++)
       {
          matrix.setElementat(m,n,z*v);
          v++;
          z *= -1; 
       }
    }
    
    matrix.print();
    

    Nun habe ich wie folgt ein neues Problem.
    Wir sollten der CMatrix Klasse weitere Methoden hinzufügen
    und dabei

    enum
    

    benutzen.

    enum INI_MODE{INIT_ZEROS, INIT_UNIT,INIT_RAND}
    

    Die zugefügten Methoden lauten :

    CMatrix(int dm, INI_MODE mode = INIT_ZEROS);
    void operator *= (float rop);
    CMatrix& operator = (const CMatrix& rop)const;
    CMatrix operator + (const CMatrix& rop)const;
    CMatrix operator * (const CMatrix& rop)const;
    friend ostream& operator << (ostream& lop, const CMatrix& rop);
    

    Ich habe schon einige implementiert und hänge nun bei dem Zuweisungsoperator 😕

    Dafür sollten wir uns an ein Aktivitätsdiagramm halten :

    ..............................Start :

    [Speichergröße der
    Operanden stimmt nicht......(Anzeige einer Meldung)
    überein]....................(Freigeben des alten Speicherplatzes)
    ............................(Allokieren von Speicher der Größe des
    .............................rechten Operanden)
    ............................(aktualisieren des Attributs der Speichergröße)

    [Speichergröße der
    Operanden stimmt............(if schleife erfüllt)
    überein]

    [Anzahl von Zeilen oder
    Spalten stimmt nicht bei.....(aktualisieren der Attribute für
    beiden Operanden überein]....Zeilen - und Spaltenzahl)

    [Anzahl von Zeilen oder
    Spalten stimmt nicht bei.....(if Schleife erfüllt)
    beiden Operanden überein]

    .............................(Kopieren der Matrix-Elemente
    .............................des rechten Operanden in das Array
    .............................des linken Operanden)
    .............................(Der linke Operand gibt sich selbst zurück)

    ............................ Ende:

    Mein Code sind folgendermaßen aus :

    CMatrix& CMatrix ::operator = (const CMatrix& rop)const
    {
    	int m_cols2 = rop.m_cols;
    	int m_rows2 = rop.m_rows;
    	int m_size2 = m_cols2 * m_rows2;
    
    	double* m_Array;
    	m_Array = new double [m_size2];
    
    	if (m_size2 == rop.m_size)
    	{
    		if (m_cols2 == rop.m_cols && m_rows2 == rop.m_rows)
    		{
    			int v = rop.getArrayIndex(rop.m_rows, rop.m_cols);
    			int z = rop.getArrayIndex(m_rows2, m_cols2);
    
    				for(int m = 1; m<=rop.m_rows; m++)
    				{
    					for(int n=1; n<=rop.m_cols ;n++)
    					{
    						m_pArray[v] = m_Array[z];
    
    					}
    
    				}
    
    		}
    
    	}
    	else if (m_size2 != rop.m_size )
    	{
    		cout << "veraendere Groesse der Matrix!"<<endl;
    		delete [] m_Array;
    		m_Array = new double [rop.m_size];
    
    		if (m_cols2 != rop.m_cols && m_rows2 != rop.m_rows)
    		{
    			m_cols2 = rop.m_cols;
    			m_rows2 = rop.m_rows;
    
    			int v = rop.getArrayIndex(rop.m_rows, rop.m_cols);
    			int z = rop.getArrayIndex(m_rows2, m_cols2);
    
    			for(int m = 1; m<=rop.m_rows; m++)
    			{
    				for(int n=1; n<=rop.m_cols ;n++)
    				{
    
    					m_pArray[v] = m_Array[z];
    				}
    
    			}
    		}
    
    	}
    
    }
    

    Ich glaube ich hab ein Problem mit der Vorstellung welcher operand rechts und welcher Links steht 😕 das im Parameter übergebene Objekt ist das der rechte
    oder der Linke Operand? 😕
    Zu dem erhalte ich den Fehler no return..aber einen der Zeiger zurückzugeben funktioniert nicht :S

    weiß jemand einen Rat?

    Vielen Dank und tut mir leid, dass ich wieder mit was neuem beginne :S



  • // links |   rechts
       x     +     y;
       x.operator+(y); // Die obere Variante ist nur die faule, schönere Schreibweise.
    

    Offensichtlich ist der Operand rechts vom Operator der Parameter. Und der Operand links vom Operator ist das Objekt, das verändert wird. 😉

    Logischerweise willst du das veränderte Objekt zurückgeben, für den Fall, dass andere Funktionen sofort mit dem veränderten Objekt weiterarbeiten können, also return *this;



  • + als Operator zu wählen, war natürlich doof. Denk dir einfach = statt + in meinem Beispiel. 😃


Anmelden zum Antworten