Segmentation fault/SIGSEGV/ Speicherzugriffsfehler



  • Hi Leutz,

    ich hab ein zweites Problem mit meinem Programm von hier:http://www.c-plusplus.net/forum/288066-20?sid=f36e40c5191825fe2e2e8bad237f5dac

    Ich hab mittlerweile ein wenig überarbeitet und unten die aktuelle Version reingestellt. Wie schon im verlinkten Post gesagt, brauchen wir uns über die Sinnhaftigkeit der Aufgabenstellung nicht zu unterhalten. Da gibts nicht viel Sinnvolles.(inkl der Umsetzung)

    Meine Frage: Wenn ich das Programm kompiliere bekomme ich bei MatrixC.print bzw, wenn ich die Zeile (23 in der main.cpp) auskommentiere beim Aufruf von MatrixD.print den Fehler: Segmentation fault.
    In den Funktionen transpose und den globalen überladenen arithmetischen operator+ bzw operator* (alle matrix.cpp), erstelle ich via new neue Objekte und übergebe diese. Meiner Meinung nach müssten die Objekte und damit ihr Speicherbereich deshalb weiterhin gültig sein, und bei der Zuweisung MatrixD= bzw. MatrixC= müssten, meiner Meinung nach, auch die Adressen an die entsprechenden Pointer (mat) weitergegeben werden. Offensichtlich ist das OS da anderer Meinung... 🙄

    Deshalb hätte ich gern eure Meinung gehört, thx!

    matrix.hpp

    #ifndef _MATRIX_H_
    #define _MATRIX_H_
    #include <iostream>
    #include <cassert>
    using namespace std;
    class Zeile
    {
    private:
        int *z;
        int size;
    public:
    // zu implementieren: Konstruktor und Destruktor
        Zeile( int s);
        ~Zeile();
    // Indexoperator [] ist (in zwei Versionen) bereits implementiert für die Klasse Zeile
        int& operator[](int i)
        {
            assert(i >= 0 && i < size);
            return z[i];
        }
        const int& operator[](int i) const
        {
            assert(i >= 0 && i < size);
            return z[i];
        }
    };
    class Matrix
    {
    private:
        Zeile **mat; // Zeiger auf "Zeilen"-Vektor
        int nrows, ncols; // Zeilen- und Spaltenzahl
        void init(int z, int s);
    public:
    //zu implementieren: Zwei Konstruktoren, ein Kopierkonstruktor und ein Destruktor
        Matrix( int _nrows , int _ncols);
        Matrix( int z, int s, int wert);
        Matrix( const Matrix& m);
        ~Matrix();
        int getRows()const
        {
            return nrows;
        }
        int getCols()const
        {
            return ncols;
        }
    // zu implementieren: Indexoperator [] (in zwei Versionen) für die Klasse Matrix
        Zeile& operator[](int i)
        {
            assert(i >= 0 && i < nrows);
            return **(mat+i);
        }
        const Zeile& operator[](int i) const
        {
            assert(i >= 0 && i < nrows);
            return **(mat+i);
        }
    // zu implementieren: Transponierte der Matrix
        Matrix transpose();
    // zu implementieren: Ausgabe, Addition und Multiplikation
        void print();
        friend Matrix operator+(const Matrix& ma, const Matrix& mb);
        friend Matrix operator*(const Matrix& ma, const Matrix& mb);
    };
    #endif
    

    matrix.cpp

    #include "matrix.hpp"
    
    Zeile::Zeile(int s)
    {
        z=new int[s];//entgegen der Aufgabenstellung kann man hier kein double-Feld reservieren wenn z vom Typ int ist
        size=s;
    }
    Zeile::~Zeile()
    {
        delete[] z;
    }
    void Matrix::init(int z, int s)
    {
        nrows=z;
        ncols=s;
        mat=new Zeile* [z];
        for(int i=0; i<z; i++)
            mat[i]=new Zeile(s);
    }
    Matrix::Matrix(int _nrows, int _ncols)
    {
        this->init(_nrows,_ncols);
    }
    Matrix::Matrix(int z, int s, int wert)
    {
        this->init(z,s);
        for (int i=0; i<z; i++)
            for(int j=0; j<s; j++) (*this)[i][j]=wert;
    }
    Matrix::Matrix(const Matrix& m)
    {
        this->init(m.nrows,m.ncols);
        for(int i=0; i<m.nrows; i++)
            for(int j=0; j<m.ncols; j++) (*this)[i][j]=m[i][j];
    }
    Matrix::~Matrix()
    {
        for(int i=0; i<nrows; i++) delete mat[i];
        delete[] mat;
    }
    Matrix operator+(const Matrix& ma, const Matrix& mb)
    {
        assert(ma.nrows==mb.nrows && ma.ncols==mb.ncols);
        Matrix *result;
        result= new Matrix(ma.nrows,ma.ncols,0);
        for(int i=0; i<ma.nrows; i++)
            for(int j=0; j<ma.ncols; j++)
                (*result)[i][j]=ma[i][j]+mb[i][j];
        return (*result);
    }
    Matrix operator*(const Matrix& ma, const Matrix& mb)
    {
        assert(ma.nrows==mb.ncols && ma.ncols==mb.nrows);
        Matrix *result;
        result= new Matrix(ma.nrows,ma.nrows,0);
        for(int x=0; x<ma.nrows; x++)
            for(int i=0; i<ma.nrows; i++)
            {
                int zwischenergebnis=0;
                for(int j=0; j<ma.ncols; j++)
                    zwischenergebnis+=ma[x][j]*mb[j][i];
                (*result)[x][i]=zwischenergebnis;
            }
        return (*result);
    }
    Matrix Matrix::transpose()
    {
        Matrix *trans_matrix;
        trans_matrix=new Matrix(this->ncols,this->nrows);
        for(int i=0; i<this->ncols; i++)
            for(int j=0; j<this->nrows; j++)
                (*trans_matrix)[i][j]=(*this)[j][i];
        return (*trans_matrix);
    }
    void Matrix::print()
    {
        for(int i=0; i<this->nrows; i++)
        {
            for(int j=0; j<this->ncols; j++)
                cout << (*this)[i][j] << "\t";
            cout << endl;
        }
    }
    

    main.cpp

    #include <iostream>
    #include "matrix.cpp"
    
    using namespace std;
    
    int main()
    {
        cout << "Hello world!" << endl;
        Matrix MatrixA(3,4);
        for(int i=0; i<MatrixA.getRows(); i++)
            for(int j=0; j<MatrixA.getCols(); j++)
                MatrixA[i][j]=(j+1)+(i*10);
        cout << "MatrixA ist momentan: "<<endl;
        MatrixA.print();
        cout << "============================"<<endl;
        Matrix MatrixB(MatrixA);
        cout << "MatrixB ist momentan: "<<endl;
        MatrixB.print();
        cout << "============================"<<endl;
        Matrix MatrixC(MatrixA.getRows(),MatrixA.getCols());
        MatrixC=MatrixA+MatrixB;
        cout << "MatrixC ist momentan: "<<endl;
        MatrixC.print();
        cout << "============================"<<endl;
        Matrix MatrixD(1,1,1);
        MatrixD=MatrixB.transpose();
        cout << "MatrixD ist momentan: "<<endl;
        MatrixD.print();
        cout << "============================"<<endl;
        return 0;
    }
    


  • Du hast in deinen Operatoren ein Speicherleck (ich tippe auf Java-Vorschädigung) und keinen Zuweisungsoperator.

    PS: Dir ist hoffentlich klar, daß für die Matrixmultiplikation andere Randbedingungen gelten 😉



  • CStoll schrieb:

    Du hast in deinen Operatoren ein Speicherleck (ich tippe auf Java-Vorschädigung) und keinen Zuweisungsoperator.

    PS: Dir ist hoffentlich klar, daß für die Matrixmultiplikation andere Randbedingungen gelten 😉

    Hmm kannst du das spezifizieren? Meine Aussage mit der Zuweisung war auf die main.cpp bezogen. Also dass es da iwo nen Speicherleck gibt ist ja klar, die Frage, die sich mir stellt ist: wo?

    Was meinst du in Bezug auf die Randbedingungen?



  • Kiigass schrieb:

    CStoll schrieb:

    Du hast in deinen Operatoren ein Speicherleck (ich tippe auf Java-Vorschädigung) und keinen Zuweisungsoperator.

    PS: Dir ist hoffentlich klar, daß für die Matrixmultiplikation andere Randbedingungen gelten 😉

    Hmm kannst du das spezifizieren? Meine Aussage mit der Zuweisung war auf die main.cpp bezogen. Also dass es da iwo nen Speicherleck gibt ist ja klar, die Frage, die sich mir stellt ist: wo?

    Das Speicherleck tritt auf, weil du die Objekte nicht wieder freigibst, die in den Rechenfunktionen angefordert werden.
    Dein Problem ist: beim Aufruf return (*result); wird von deinem dynamisch angelegten Objekt eine Kopie (nennen wir sie "temp") nerzeugt, die dann zurückgegeben wird. Diese Kopie wird dann an MatrixC zugewiesen (weil du keinen Operator dafür hast, stellt der Compiler einen bereit). Danach wird "temp" zerstört und gibt die Matrixdaten frei, die MatrixC noch benötigt.

    Was meinst du in Bezug auf die Randbedingungen?

    Es geht um die Assert-Bedingungen in dem Operator - Die Multiplikation ist zulässig, wenn l.Spalten==r.Zeilen ist.



  • CStoll schrieb:

    Kiigass schrieb:

    CStoll schrieb:

    Du hast in deinen Operatoren ein Speicherleck (ich tippe auf Java-Vorschädigung) und keinen Zuweisungsoperator.

    PS: Dir ist hoffentlich klar, daß für die Matrixmultiplikation andere Randbedingungen gelten 😉

    Hmm kannst du das spezifizieren? Meine Aussage mit der Zuweisung war auf die main.cpp bezogen. Also dass es da iwo nen Speicherleck gibt ist ja klar, die Frage, die sich mir stellt ist: wo?

    Das Speicherleck tritt auf, weil du die Objekte nicht wieder freigibst, die in den Rechenfunktionen angefordert werden.
    Dein Problem ist: beim Aufruf return (*result); wird von deinem dynamisch angelegten Objekt eine Kopie (nennen wir sie "temp") nerzeugt, die dann zurückgegeben wird. Diese Kopie wird dann an MatrixC zugewiesen (weil du keinen Operator dafür hast, stellt der Compiler einen bereit). Danach wird "temp" zerstört und gibt die Matrixdaten frei, die MatrixC noch benötigt.

    Was meinst du in Bezug auf die Randbedingungen?

    Es geht um die Assert-Bedingungen in dem Operator - Die Multiplikation ist zulässig, wenn l.Spalten==r.Zeilen ist.

    thx, das mit dem Speicherproblem kann ich also vermutlich nur lösen wenn ich ne Referenz auf mein dynamisch erzeugtes Objekt übergebe?

    Wegen der Randbedingung: Das hab ich doch drin!?(oder meinst, dass meine Bedingung noch eine zusätzliche Klausel hat?)



  • Nein, das Speicherproblem kannst du nur lösen, indem du deiner Matrix-Klasse einen vernünftigen Zuweisungs-Operator verschaffst. (such mal nach "Rule of Three" bzw. "Regel der großen Drei" für weitere Erklärungen)
    Die Rückgabewerte der Operatoren per new anzufordern ist Unsinn und führt nur zu Speicher-Lecks, die du nicht mehr schließen kannst.

    Und was die Multiplikation angeht - da ist deine Bedingung zu streng (ich hatte übersehen, daß du die Dimensionen kreuzweise vergleichst). Die Multiplikation einer 3x5 und 5x7 Matrix ist erlaubt und ergibt eine 3x7 Matrix.


Anmelden zum Antworten