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); }; #endifmatrix.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 Aufrufreturn (*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.Zeilenist.
-
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 Aufrufreturn (*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.Zeilenist.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.