Struktur als Eingabe UND Rückgabewert einer Funktion !?



  • Hallo,

    ich habe eine Struktur Matrix gebastelt, die ich in einer Funktion als Eingabe- und Rückgabewert verwenden möchte.
    Ist das möglich? Falls ja, wie?

    Genauer: Ich möchte die Schursche Normalform einer Matrix A bestimmen. Dazu benötige ich eine Struktur Matrix, eine Funktion die mir die QR-Zerlegung meiner Matrix berechnet und in der Main-Funktion möchte ich das Q meiner QR-Zerlegung in eine Iteration einbauen.
    Die QR-Zerlegung erhält als Eingabe die Matrix A.

    Vielen Dank schonmal!

    Viele Grüße



  • Übergib einfach einen Pointer auf deine Struktur oder eine Referenz an deine Funktion.



  • Danke. Wie mache ich das?
    Kannst du das bitte an einem Beispiel zeigen? (Bin wie mein Name sagt nicht gerade bewandert...)



  • struct Matrix {
    };
    
    Matrix *SchurscheAlsRef(const Matrix & m) { ... }
    Matrix *SchurscheAlsPointer(const Matrix *m) { ... }
    
    Matrix m1;
    Matrix *m2 = SchurscheAlsRef(m);
    Matrix *m3 = SchurscheAlsPointer(&m);
    


  • Ganz, ganz böse. Returne niemals einen Zeiger oder eine Referenz auf ein lokales Objekt!



  • Wenn ich keine Zeiger oder Referenz einem lokalen Objekt zuweisen soll, wie geht's dann?

    Ich sende mal den Programmcode den ich habe (der geht soweit), ich möchte die Funktion "schmidtortho" (QR-Zerlegung) in mein Programm einbauen. Ihr braucht die Funktion nicht nachzuvollziehen, ich glaube das ist nicht nötig.
    Muss nicht am Ende der Funktion noch so etwas wie " *schmidtortho = Q" stehen? (Ich möchte Q als Matrix zurückliefern.)

    // Schmidt-Orthogonalisierung berechnen
    Matrix *schmidtortho(const struct Matrix &A) {
      int h,i,j;
      double qa[NMAX*NMAX], ra[NMAX*NMAX], va[NMAX*NMAX];
      struct Matrix Q, R, V;
      double *Aptr, *Aptr3;
    
      double *Qptr, *Qptr2, *Qptr3, *Qptr4;
      double *Rptr, *Rptr3;
      double f, nor;
    
      strcpy(Q.name,"Q");
      Q.m = A.m; Q.n = A.n; Q.a = qa;
    
      strcpy(R.name,"R");
      R.m = A.n; R.n = A.n; R.a = ra;
    
      // Schleife über alle Spalten j der Matrix A
      Aptr = A.a;
      Qptr = Q.a; 
      Rptr = R.a;
      for (j=0; j<Q.n; j++) {
        Aptr3 = Aptr; // j-te Spalte
        Qptr3 = Qptr; // j-te Spalte
        for (i=0; i<Q.m; i++) {
          *Qptr3 = *Aptr3; // Q(:,j)=A(:,j), Spalte j von A nach Q kopieren
          Aptr3 += Q.n; Qptr3 += Q.n;
        }
    
        // q_j = a_j - sum_{h=1}^{j-1} <a_j, q_h> q_h
        Qptr2=Q.a;  // h-te Spalte 
        Rptr3=Rptr; // j-te Spalte
        for (h=0; h<j && h<Q.m; h++) {
          Aptr3=Aptr; // j-te Spalte
          Qptr4=Qptr2; // h-te Spalte
          f=0.;
          for (i=0; i<Q.m; i++) {
    	f += *Aptr3 * *Qptr4;
    	Aptr3+=Q.n; Qptr4+=Q.n;   // A(:,j)^T * Q(:,h)
    	} 
    
          Qptr3=Qptr; // j-te Spalte
          Qptr4=Qptr2; // h-te Spalte
    
          for (i=0; i<Q.m; i++) {
    	*Qptr3 -= f* *Qptr4;
    	Qptr3 += Q.n; Qptr4 += Q.n; // Q(:,j)=Q(:,j) - f*Q(:,h)
          }
    
          *Rptr3 = f; 
          Rptr3 += R.n; // R(h,j)
          Qptr2++; // nächste h-Spalte
        }
        // Normierungsfaktor berechnen
        Qptr3=Qptr; // j-te Spalte
        *Rptr3 = 0.; // R(j,j) = 0.
        for (i=0; i<Q.m; i++) {
          *Rptr3 += *Qptr3 * *Qptr3;
          Qptr3 += Q.n; // R(j,j) = Q(:,j)^T * Q(:,j)
        } 
    
        Qptr3 = Qptr; // j-te Spalte
        if (*Rptr3 > 1.e-10) {
          *Rptr3 = sqrt(*Rptr3); // sqrt(R(j,j))
          //      printf("Rjj %f %f", *Rptr3, f);
    
          // Normieren der Spalte j von Q
          for (i=0; i<Q.m; i++) {
    	*Qptr3 /= *Rptr3;   
    	Qptr3 += Q.n; // Q(:,j)=Q(:,j) / R(j,j)
          }
        } 
        else {
          *Rptr3 = 0.;  // R(j,j) = 0.
          for (i=0; i<Q.m; i++) {
    	*Qptr3 = 0.; 
    	Qptr3 += Q.n; // Q(:,j)=0.
          }
        }
        Rptr3+= Q.n;
        for (h=j; h<Q.n; h++) {
          *Rptr3 = 0.; // R(j+1:Q.n , j)=0.
          Rptr3 += Q.n;
        } // Spalten q_j und r_j sind berechnet
    
        Aptr++; Qptr++; Rptr++; // nächste j-te Spalte
      } // Ende der j-Schleife
    
      // Probe rechnen: V=A; V=V-Q*R, 
      V.m = A.m; V.n = A.n; V.a = va;
      Aptr = A.a; Aptr3 = V.a;
      for (i=0; i < A.m*A.n; i++) *(Aptr3++) = *(Aptr++); // V=A;
      VminusQR(Q,R,V);
      nor = norminf(V);
    }
    

    Die Struktur Matrix sieht so aus:

    struct Matrix {  
      int m,n; // Zeilen- und Spaltenanzahl der Matrix
      double *a; // Zeiger auf 1. Eintrag in der Matrix
      char name[7]; // Matrixname mit <=6 Buchstaben, Init. mit strcpy
    };
    

    Und mein Hauptprogramm etwas verkürzt:

    int main ( )
    { 
      const int nmat =2;  // Anzahl der Matrizen
      struct Matrix mat[nmat]; // Array von Matrizen
    
      // Initialisierung der Matrizen 
      // Speicherformat: zeilenweise, jedoch als eindimensionale Arrays
      double A[] = { 
        -3.,1.,
        1.,2. };
      double B[] = {
             0.,0.,
             0.,0.};
    
      // Initialisierung des Matrizen-Arrays mit Namen, Dimensionen und Einträgen
      strcpy(mat[0].name,"A");
      mat[0].m = 2; mat[0].n = 2; mat[0].a = A;
      strcpy(mat[1].name,"B");
      mat[1].m = 2; mat[1].n = 2; mat[1].a = B;
    
      UND HIER SOLL HIN:  mat[1] = schmidtortho (mat[0])
    
    }
    

    Ich hoffe dass war jetzt nicht zu lang... danke nochmal!



  • Code, der für das Problem viel zu lang, fragwürdig eingerückt und ohne Syntaxhighlighting da steht, wird eher selten angeschaut. 😉

    Also benutze [cpp]-Tags und versuche, nur den relevanten Teil zu posten. Deine Matrixberechnung ist für das Problem irrelevant. Zudem würde ich dir raten, die Funktion zu unterteilen, dann wird der Algorithmus auch übersichtlicher. Abgesehen davon könntest du das Ganze ein wenig objektorientierter gestalten. Wenn du schon in C++ programmierst, kannst du von so vielen Zeigern und Arrays wegkommen und Probleme in Klassen gliedern. Statt des unsicheren strcpy und C-Strings wäre std::string eine gute Möglichkeit. 🙂

    Zu deinem Problem: Ich rate davon ab, Zeiger zurückzugeben, wenn es nicht nötig ist. Das erhöht nämlich nur die Gefahr von ungültigem Zugriff (wegen lokaler Variablen) oder vergessener Freigabe (bei selbst allokiertem Speicher).

    Matrix func() // Rückgabetyp Matrix - kein Zeiger, keine Referenz.
    {
        Matrix m; // hier brauchst du KEIN struct vorne dran
        ...       // mache etwas mit m
        return m; // gib m als Kopie zurück.
    }
    


  • OK, ein weiterer Versuch, vielleicht ists jetzt kurz genug. 🙂

    C++--Neuling schrieb:

    Wenn ich keine Zeiger oder Referenz einem lokalen Objekt zuweisen soll, wie geht's dann?

    Ich sende mal den Programmcode den ich habe (der geht soweit), ich möchte die Funktion "schmidtortho" (QR-Zerlegung) in mein Programm einbauen. Ihr braucht die Funktion nicht nachzuvollziehen, ich glaube das ist nicht nötig.
    Muss nicht am Ende der Funktion noch so etwas wie " *schmidtortho = Q" stehen? (Ich möchte Q als Matrix zurückliefern.)

    [cpp]
    // Schmidt-Orthogonalisierung berechnen
    Matrix *schmidtortho(const struct Matrix &A) {
      struct Matrix Q;
      strcpy(Q.name,"Q");
      
      MATRIX Q WIRD VERARBEITET...
      Q SOLL ALS RÜCKGABEWERT DER FUNKTION DIENEN. (Wie geht das?)
    }
    [/cpp]
    

    Die Struktur Matrix sieht so aus:

    [cpp]
    struct Matrix {  
      int m,n; // Zeilen- und Spaltenanzahl der Matrix
      double *a; // Zeiger auf 1. Eintrag in der Matrix
      char name[7]; // Matrixname mit <=6 Buchstaben, Init. mit strcpy
    };
    [/cpp]
    

    Und mein Hauptprogramm etwas verkürzt:

    [cpp]
    int main ( )
    { 
      const int nmat =2;  // Anzahl der Matrizen
      struct Matrix mat[nmat]; // Array von Matrizen
    
      // Initialisierung der Matrizen 
      // Speicherformat: zeilenweise, jedoch als eindimensionale Arrays
      double A[] = { 
        -3.,1.,
        1.,2. };
      double B[] = {
             0.,0.,
             0.,0.};
    
             
      // Initialisierung des Matrizen-Arrays mit Namen, Dimensionen und Einträgen
      strcpy(mat[0].name,"A");
      mat[0].m = 2; mat[0].n = 2; mat[0].a = A;
      strcpy(mat[1].name,"B");
      mat[1].m = 2; mat[1].n = 2; mat[1].a = B;
      
      UND HIER SOLL HIN:  mat[1] = schmidtortho (mat[0])
    
    }
    [/cpp]
    

    Ich hoffe dass war jetzt nicht zu lang... danke nochmal!



  • Per value zurückgeben:

    Matrix schmidtortho(const Matrix& A)
    {
        Matrix Q;
        ...
        return Q;
    }
    

    Lies lieber noch ein Stückchen weiter in deinem Buch.



  • Steht schon weiter oben. 😉

    Aber irgendwie beschleicht mich das Gefühl, C++-Neuling kann nur mit konkreter Hilfe (d.h. wir sollen seinen Code vervollständigen) etwas anfangen. Vielleicht täusche ich mich aber auch.



  • Danke. Klappt jetzt, muss noch andere Funktionen schreiben, ich versuchs aber erstmal alleine. 🙂

    @Nexus: Sorry, hatte das nicht richtig zur Kenntnis genommen. Aber den Code sollt ihr mir nicht schreiben.

    @Michael: Hab das in meinem Buch nicht gefunden.

    So wie ihr das geschrieben habt ist das für mich der einfachst denkbare Weg, ich dachte das hätte ich so schon probiert... 🙂


Log in to reply