Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Matrix-Vektormultiplikation stürzt dauernd ab!

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
11.01.2009, 19:05 Uhr
~anfaenger09
Gast


hallo zusammen,

seit tagen bearbeite ich eine aufgabe (wortlaut siehe unten), bei der durch die verwendung von klassen und die überladung der ein- und ausgabeoperatoren eine matrix mit einem vektor multipliziert werden soll.

den code habe ich fertiggeschrieben, sodass er vollständig compiliert werden kann und das programm auch anspringt - jedoch stürzt es an allen relevanten stellen immer ab, z b wenn ich die matrix eingeben will oder die lösung ausgeben will. bei der ausführung der funktion norm() erscheint ein text im windows explorer ("This application..."), den ich jedoch nie lesen kann, da sich das fenster sofort schließt. auch die eingabe des vektors ist fehlerbehaftet, da hier maximal drei komponenten eingelesen werden können und das programm danach auch abbricht.

ich hoffe hier kann mir jemand helfen, da ich alleine echt nicht mehr weiter weiß und die zeit auch so langsam knapp wird

fehler dürften bei der überladung der operatoren sein und ich vermute, dass etwas mit den variablen n / dim nicht stimmt.

danke!


Zitat:

Implementieren Sie zwei Klassen matrix und vector.

Die Klasse matrix soll folgendes enthalten (verwenden Sie keine inline Funktionen):

- Als private Datenelement:
- Ein (n x n)-dimensionales Feld daten mit n2 Komponenten vom Typ double**.
- Eine Variable n vom Typ int, die die Dimension des Feldes abspeichert.

- Als public Elementfunktionen:
- Einen Konstruktor mit einem Argument vom Typ int, für die Dimension der Martix
und einen Argument vom Typ double zur Initialisierung der Komponenten. Dabei soll jede Komponente der Matrix den Wert des Arguments vom Typ double erhalten. Des Weiteren achten Sie darauf, dass die Matrix dynamisch erzeugt wird. Als Default-Wert soll Null gewählt werden.
- Eine Elementfunktion norm() ohne Argumente mit Ergebnistyp double, die die Spaltenbetragssummennorm des aufrufenden Objektes berechnet.
- Einen Multiplikationsoperator * mit einem Argument vom Typ vector und Ergebnistyp vector, der das Produkt einer Matrix mit einem Vektor, wie oben beschrieben, berechnet.

- Als friend Funktion:
- Einen Operator >> zur Eingabe einer Matrix von einem istream. Dabei soll die Matrix zeilenweise eingelesen werden.

Implementieren Sie die Klasse vector, die folgendes enthalten soll (verwenden Sie keine inline Funktionen):

- Als private Datenelement:
- Ein Feld daten mit n Komponenten vom Typ double*.

- Als public Elementfunktionen:
- Einen Konstruktor mit einem Argument vom Typ int, für die Dimension des Vektors und einen Argument vom Typ double zur Initialisierung der Komponenten. Dabei soll jede Komponente des Vektors den Wert des Arguments erhalten. Des Weiteren achten Sie darauf, dass der Vektor dynamisch erzeugt wird. Als Default-Wert soll Null gewählt werden.
- Einen Indexoperator [] mit einem Argument vom Typ int. Bei Aufruf des Operators [] mit dem aktuellen Argument i soll als Ergebnis eine Referenz auf die i-te Komponente des Feldes zurückgegeben werden. Falls i nicht im gültigen Indexbereich liegt, soll durch den Funktionsaufruf exit(1) das Programm abgebrochen werden. Dies dient später zum Einlesen des Vektors.

- Als friend Funktionen:
- Einen Operator << zur Ausgabe eines Vektors.
- Den Multiplikationsoperator der oben beschriebenen Klasse matrix.

Schreiben Sie ein Hauptprogramm, das ein Objekt A vom Typ matrix und ein Objekt b vom Typ vector definiert und einliest. Danach soll die Spaltenbetragssummennorm von A und das Produkt A*b von A und b ausgegeben werden. Bei erfolgreicher Beendigung des Programms soll der Wert 0 an das Betriebssystem zurückgegeben werden. Vergessen Sie nicht allen dynamisch allokierten Speicherplatz wieder zu löschen.




C++:
#include <iostream>
using namespace std;

class vector;

class matrix
{
      private:
      int n;
      double** daten;
      
      public:
      matrix(int n, double = 0);
      ~matrix();
      double norm();
      vector operator *(vector x);
      
      friend istream& operator >> (istream& is, matrix& x);
};

class vector
{      
      private:
      int n;
      double* daten;
      
      public:
      vector(int n, double = 0);
      ~vector();
      double& operator [](int i);
      
      friend vector matrix::operator *(vector x);
      friend ostream& operator << (ostream& os, vector& x);
};

matrix::matrix(int n, double defaultzero)
{                  
      double** daten = new double* [n];
      for(int i=0; i<n; i++) daten[i] = new double [n];
      
      for(int i=0; i<n; i++) for(int j=0; j<n; j++) daten[i][j]=defaultzero;        
}

matrix::~matrix()
{
      for(int i=0; i<n; i++) delete[] daten[i];
      delete[] daten;          
}

double matrix::norm()
{
      double* summe = new double [n];
          
      for(int j=0; j<n; j++) summe[j]=0;
      
      for(int j=0; j<n; j++) for(int i=0; i<n; i++) summe[j] += daten[i][j];
      
      for(int j=n-1; j>=0; j--) summe[j]=max(summe[j],summe[j+1]);
      
      double ret = summe[0];
      
      delete[] summe;  
      
      return ret;
}

vector matrix::operator *(vector x)
{      
      vector l(n);
      
      for(int i=0; i<n; i++) for(int j=0; j<n; j++) l[i] += daten[i][j]*x.daten[j];
      
      return l;
}

istream& operator >> (istream& is, matrix& x)
{
      cout << "Bitte geben Sie die Matrix zeilenweise ein! \n \n";
        
      for(int i=0; i<x.n; i++) for(int j=0; j<x.n; j++) is >> x.daten[i][j];

      return is;
}

double& vector::operator [](int i)
{
      if(i>=n) exit(1);        
      return daten[i];
}

ostream& operator << (ostream& os, vector& x)
{
      for(int i=0; i<x.n; i++) os << x.daten[i] << "\n";
      
      return os;  
}

vector::vector(int n, double defaultzero)
{                                                    
      double* daten = new double[n];
      
      for(int i=0; i<n; i++) daten[i]=defaultzero;
}

vector::~vector()
{
      delete[] daten;
}

int main()
{
      int dim;
      cout << "Bitte geben Sie die Dimension ein! \n \n";
      cin >> dim;
      cout << "\n";    
    
      matrix A(dim);
      vector b(dim);
      
      cin >> A;
      for(int i=0; i<dim; i++) cin >> b[i];
      
      cout << A.norm();
      
      vector l = A*b;
      cout << l;
    
      system("PAUSE");
      return 0;      
}




Bearbeitung von 0xdeadbeef:

Smileys, ThWboard-Code eingeschaltet


Dieser Post wurde am 11.01.2009 um 19:38 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
11.01.2009, 19:49 Uhr
0xdeadbeef
Gott
(Operator)


Du setzt in vector::vector this->n nicht auf n. (Ich würde dir übrigens raten, verschiedene Namen für Member- und lokale Variablen zu benutzen) Dementsprechend ist bei der Eingabe des Vektors b.n == 0, und b[i] ruft exit auf. Analog verdeckt die lokale Deklaration double **daten in beiden Konstruktoren die Membervariable, in die du eigentlich schrieben willst.

Übrigens, exit ist in C++ eine ziemlich ungesunde Funktion. Objekte mit statischer storage duration werden noch zerstört, aber die Destruktoren aller Objekte, die auf dem Stack liegen, werden nicht ausgeführt. Das ist vielleicht nicht besonders kritisch, wenn du bloß Heap-Speicher wieder freigeben musst, aber jetzt stell dir vor, du hast einen Socket offen oder shared memory angefordert. Besser wäre hier:

C++:
#include <stdexcept>

// ...

double& vector::operator [](int i)
{
  if(i>=n) throw std::out_of_range("i in vector::operator[](int)");
  return daten[i];
}


Der String wird als diagnostische Meldung ausgegeben, wenn die Exception nicht gefangen wird. Was du da reinschreibst, ist dir überlassen, aber für diesen Zweck sollte der Funktionsname eigentlich aussagekräftig genug sein. Wenn ich den oben beschriebenen Bug drin lasse und die Exception einfüge, sieht der Aufruf bei mir aus wie folgt:

Code:
$ ./a.out
Bitte geben Sie die Dimension ein!

3

Bitte geben Sie die Matrix zeilenweise ein!

terminate called after throwing an instance of 'std::out_of_range'
  what():  i in vector::operator[](int)
Abgebrochen


Was da bei dir genau rauskommt, hängt vom Compiler ab, aber etwas vergleichbares wird es im Zweifel sein.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 11.01.2009 um 20:05 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
11.01.2009, 20:14 Uhr
~anfaenger09
Gast


hallo,

danke für deine schnelle antwort. leider weiß ich nicht so genau, was du meinst. kannst du mir sagen, wie ich das n richtig setzen muss? insbesondere die befehle this und -> bereiten mir noch schwierigkeiten.

mit der einen änderung wär doch aber auch nur eines von vielen problemen gelöst, oder? wenn ich die bereiche mit dem vektor alle ausklammere und beispielsweise nur die matrix einlese oder die matrix überall mit null besetzt lasse und norm() anwende, kommt es auch zum absturz.

danke!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
11.01.2009, 20:43 Uhr
0xdeadbeef
Gott
(Operator)


Ich geb's dir mal für den Vektor vor:

C++:
vector::vector(int n, double defaultzero)
{
  this->n = n;                                                    
  daten = new double[n];
      
  for(int i=0; i<n; i++) daten[i]=defaultzero;
}


this ist ein Zeiger auf das Objekt, in dessen Methode du dich gerade befindest. this->n ist das selbe wie (*this).n, also n innerhalb des Objektes, auf das this zeigt - das ist nur deshalb notwendig, weil der Parameter n die Membervariable verdeckt. daten darf aus dem gleichen Grund nicht lokal deklariert werden, sonst verdeckt die lokale Variable daten die Membervariable, und dein ganzer neu angelegter Speicher geht verloren, sobald der Konstruktor vorbei ist. Hier, wo ich die lokale Deklaration entfernt habe, ist daten das selbe wie this->daten.

Es ist sinnvoll, solche Verdeckungen zu vermeiden. Du könntest zum Beispiel

C++:
vector::vector(int param_n, double defaultzero) {
  n = param_n
  // ...
}


schreiben. Häufig benutzt man auch eine besondere Nomenklatur für Membervariablen; ich halte es da üblicherweise mit der GNU-Konvention. Das sieht dann so aus:

C++:
class vector
{      
private:
  int n_;
  double *daten_;

      
public:
  vector(int n, double = 0);
  ~vector();
  double& operator [](int i);
      
  friend vector matrix::operator *(vector x);
  friend ostream& operator << (ostream& os, vector& x);
};


Andere bevorzugen m_ als Präfix, also m_n und m_daten. Es ist ein bisschen Geschmackssache, aber es verhindert, wenn man es nicht gerade darauf anlegt, solche Fehler.

Und, das sollte ich zumindest noch erwähnen, es ist eigentlich schöner, das ganze in der Konstruktor-Initialisierungsliste zu machen, wenn nicht gerade ein Grund dagegen spricht, also

C++:
vector::vector(int n, int defaultzero)
  : n_(n) {
  // ...
}


Wirklich notwendig ist das aber eigentlich nur, wenn du Memberobjekte hast, die keinen Defaultkonstruktor mitbringen, oder Member-Referenzen.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 11.01.2009 um 20:45 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
11.01.2009, 21:41 Uhr
~anfaenger09
Gast


besten dank! du hast meinen tag gerettet! :-)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: