Rückgabetyp abhängig von der Eingabe



  • Wohl eher ein struct, in dem ein Zeiger und eine Typinformation enthalten ist, denn ein "Rück"Cast von void* auf irgendwas ist nur definiert für denselben Typ vom "Hin"Cast. Also in etwa

    enum Typen {TYPD1,TYPD2,TYPV1,TYPV2};
    
    struct typ {
    enum Typen typ;
    void *zeiger;
    };
    
    struct typ funktion(bla....)
    {
      struct typ r;
      ...
      r.typ = TYPD1;
      r.zeiger = hierirgendeinpassenderzeiger;
      ...
      return r;
    }
    


  • CJens schrieb:

    @dot: Auf den Flächenelementen soll später eine partielle Differentialgleichung diskretisiert werden. Im Zellmittelpuntk wird deren Wert gespeichert. Jetzt ist es so, dass zur Berechnung des Wertes im Zellmittelpunkt die Gradienten zu den Nachbarwerten berechnet werden. Dazu ist die Nummerierung entscheident, da die daraus resultierende Koeffizientenmatrix dann diagonaldominanter wird und man mit effizienteren Lösungsalgorithmen für große, dünnbesetzte Matrizen arbeiten kann (z.B. SOR, ILU, CG-Verfahren). Also, es wäre toll, wenn der Wert von Element #5 von den Elementen 3,4,6 und 7 abhängt. Der Wert von Element #6 von 4,5,7 und 8 usw.
    Dann erhalte ich eine Matrix, in der nur die Hauptdiagonale und einige Nebendiagonalen mit Werte != 0 besetzt sind.
    Am Ende kommt da eine Matrix N x N Matrix raus, wobei N locker 5 Mio. betragen kann. Da kann man mit dem Gauß-Eliminationsverfahren nicht mehr ran gehen - das würde einige hundert Jahre dauern. Außerdem ist es nachteilig, hier alle Einträge der Matrix zu speichern.

    Aber wieso genau brauchst du dann eine Funktion, die zwei verschiedene Typen zurückgeben kann? Mach doch einfach Funktionen, die dir jeweils sagen, ob es sich um ein Quad oder Dreieck handelt und dann eben zwei Funktionen, die entweder ein Quad oder ein Dreieck returnen!?



  • Hallo Dirk,

    das klingt genau danach, wonach ich suche. Habe dazu mal ein kleines Beispielprogramm erstellt:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct{
    	unsigned long P1;
    	unsigned long P2;
    	unsigned long P3;
    	unsigned long P4;
    }TQuad;
    
    typedef struct{
    	unsigned long P1;
    	unsigned long P2;
    	unsigned long P3;
    }TTri;
    
    int DefineMesh(TQuad * pQuad, TTri * pTri, unsigned long * nQuad, unsigned long * nTri);
    void * ReturnElement(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber);
    
    int main(){
    TQuad * pQuad, * TestQuad;
    TTri * pTri, * TestTri;
    unsigned long nE=0;
    void *TestElement;
    
    unsigned long nQuad=0, nTri=0;
    
    DefineMesh(pQuad, pTri, &nQuad, &nTri);
    
    //Try to get Quad with index number 1 (Element number 2)
    printf("Please enter element number (0 <= x <=3):\n");
    scanf ("%i",&nE);
    
    TestElement = ReturnElement(pQuad, pTri, nQuad, nE);
    if (nE>nQuad){
    	TestTri = TestElement;
    	printf("Got triangle\n  - P1: %lu\n  - P2: %lu\n  - P3: %lu\n\n", TestTri->P1, TestTri->P2, TestTri->P3);
    } else {
    	TestQuad = TestElement;
    	printf("Got quadrilateral\n  - P1: %lu\n  - P2: %lu\n  - P3: %lu\n  - P4: %lu\n\n", TestQuad->P1, TestQuad->P2, TestQuad->P3, TestQuad->P4);
    }
    
    system("PAUSE");
    return 0;
    }
    
    void * ReturnElement(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber){
    if (ElementNumber>fnQuad){
    	return &fpTri[ElementNumber-fnQuad-1];
    } else {
    	return &fpQuad[ElementNumber-1];
    }
    }
    
    int DefineMesh(TQuad * pQuad, TTri * pTri, unsigned long * nQuad, unsigned long * nTri){
    TQuad * fpQuad = (TQuad *)calloc(2, sizeof(TQuad)), * fpQuadStart = fpQuad;
    TTri * fpTri = (TTri *)calloc(2, sizeof(TTri)), * fpTriStart = fpTri;
    
    fpQuad->P1 = 1;
    fpQuad->P2 = 2;
    fpQuad->P3 = 3;
    fpQuad->P4 = 4;
    fpQuad++;
    
    fpQuad->P1 = 4;
    fpQuad->P2 = 3;
    fpQuad->P3 = 5;
    fpQuad->P4 = 6;
    
    fpTri->P1 = 6;
    fpTri->P2 = 5;
    fpTri->P3=7;
    fpTri++;
    
    fpTri->P1 = 2;
    fpTri->P2 = 3;
    fpTri->P3 = 8;
    
    pQuad = fpQuadStart;
    pTri = fpTriStart;
    *nQuad=2;
    *nTri=2;
    return 0;
    }
    

    Das ganze läuft auch durch, jedoch bekomme ich bei egal welcher Eingabe immer Zahlen jenseits von Gut uns Böse raus. Wenn ich z.B. 1 eingebe, würde ich ja erwarten, dass ich P1: 1, P2: 2, P3: 3 und P4: 4 bekomme. Ich bekomme aber P1: 2333394051, P2: 2337338437, P3: 2337339461, P4: 3897621573. Also, ich denke er gibt mir nicht die Werte, sondern die Adressen zurück. Das verstehe ich nicht, denn fpQuad und fpTri sind ja Pointer. Ich gebe einen Pointer zurück und weise diesen dann TestTri und TestQuad zu, die ja auch Pointer sind.



  • Hallo Dirk,
    hallo Wutz,

    habe jetzt mal versucht, aus Euren beiden Vorschlägen eine Lösung zu basteln. Diese sieht wie folgt aus:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct{
    	unsigned long P1;
    	unsigned long P2;
    	unsigned long P3;
    	unsigned long P4;
    }TQuad;
    
    typedef struct{
    	unsigned long P1;
    	unsigned long P2;
    	unsigned long P3;
    }TTri;
    
    enum ElType {Tri=1, Quad};
    
    struct Typ{
    	enum ElType Typen;
    	void *Pointer;
    };
    
    int DefineMesh(TQuad **pQuad, TTri **pTri, unsigned long * nQuad, unsigned long * nTri);
    void * ReturnElement(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber);
    struct Typ ReturnElementFunc(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber);
    
    int main(){
    TQuad * pQuad, * TestQuad;
    TTri * pTri, * TestTri;
    unsigned long nE=0;
    struct Typ TestElement;
    
    unsigned long nQuad=0, nTri=0;
    
    DefineMesh(&pQuad, &pTri, &nQuad, &nTri);
    
    //Try to get Quad with index number 1 (Element number 2)
    printf("Please enter element number (0 <= x <=3):\n");
    scanf ("%i",&nE);
    
    TestElement = ReturnElementFunc(pQuad, pTri, nQuad, nE);
    if (TestElement.Typen == 1){
    	TestTri = TestElement.Pointer;
    	printf("Type: Triangle\n  - P1: %lu\n  - P2: %lu\n  - P3: %lu\n\n", TestTri->P1, TestTri->P2, TestTri->P3);
    } else {
    	TestQuad = TestElement.Pointer;
    	printf("Type: Quadrilateral\n  - P1: %lu\n  - P2: %lu\n  - P3: %lu\n  - P4: %lu\n\n", TestQuad->P1, TestQuad->P2, TestQuad->P3, TestQuad->P4);
    }
    system("PAUSE");
    return 0;
    }
    
    void * ReturnElement(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber){
    if (ElementNumber>fnQuad){
    	return &fpTri[ElementNumber-fnQuad-1];
    } else {
    	return &fpQuad[ElementNumber-1];
    }
    }
    
    struct Typ ReturnElementFunc(TQuad * fpQuad, TTri * fpTri, unsigned long fnQuad, unsigned long ElementNumber){
    	struct Typ r;
    
    	if (ElementNumber>fnQuad){
    		r.Typen = 1;
    		r.Pointer = fpTri[ElementNumber-fnQuad-1];
    	} else {
    		r.Typen = 2;
    		r.Pointer = fpQuad[ElementNumber-1];
    	}
    
    	return r;
    }
    
    int DefineMesh(TQuad **pQuad, TTri **pTri, unsigned long * nQuad, unsigned long * nTri){
    TQuad * fpQuad = (TQuad *)calloc(2, sizeof(TQuad)), * fpQuadStart;
    TTri * fpTri = (TTri *)calloc(2, sizeof(TTri)), * fpTriStart;
    
    fpTriStart = fpTri;
    fpQuadStart = fpQuad;
    
    fpQuad->P1 = 1;
    fpQuad->P2 = 2;
    fpQuad->P3 = 3;
    fpQuad->P4 = 4;
    fpQuad++;
    
    fpQuad->P1 = 4;
    fpQuad->P2 = 3;
    fpQuad->P3 = 5;
    fpQuad->P4 = 6;
    
    fpTri->P1 = 6;
    fpTri->P2 = 5;
    fpTri->P3=7;
    fpTri++;
    
    fpTri->P1 = 2;
    fpTri->P2 = 3;
    fpTri->P3 = 8;
    
    *pQuad = fpQuadStart;
    *pTri = fpTriStart;
    *nQuad=2;
    *nTri=2;
    return 0;
    }
    

    Das Ganze läuft, die Fallunterscheidung funktioniert auch, aber wieder bekomme ich für die Knotennummern total unsinnige Werte (wie bei meiner vorherigen Funktion).



  • CJens schrieb:

    r.Typen = 1;
    		r.Pointer = fpTri[ElementNumber-fnQuad-1];
    

    Welcher Compiler akzeptiert denn so was? Nicht mal eine Warnung?



  • ...der TCC als auch der LCC Compiler.

    Keine Warnung (der TCC gibt ja eh kaum Warnungen aus). Der LCC ist aber eig. schon recht empfindlich.



  • Du weist da eine Struktur einem void-Zeiger zu. Vermutlich möchtest du eigentlich die Adresse der Struktur dem Zeiger zuweisen.



  • ...einem Void Zeiger kann jeder Zeiger zugewiesen werden?
    Und ein Array ist doch lediglich ein Zeiger...



  • CJens schrieb:

    ...einem Void Zeiger kann jeder Zeiger zugewiesen werden?

    Richtig.

    CJens schrieb:

    Und ein Array ist doch lediglich ein Zeiger...

    Erstens ist das falsch. Wo immer du das her hast, vergiss es ganz schnell wieder.

    Zweitens ist fpTri[ElementNumber-fnQuad-1] weder Zeiger noch Array, sondern eine TTri-Struktur.



  • ...ein Array ist ein Zeiger auf das erste Element eines Arrays.

    Dann müsste aber

    r.Pointer = &fpTri[ElementNumber - fnQuad - 1];
    

    funktionieren. Tut es aber nicht.



  • CJens schrieb:

    ...ein Array ist ein Zeiger auf das erste Element eines Arrays.

    Du merkst, dass du da eine rekursive Definition hast?

    Und wie gesagt: Es wird oft erzählt und leider noch öfter weitererzählt, aber es stimmt einfach nicht. Verbreite bitte nicht so einen Unsinn.

    CJens schrieb:

    Tut es aber nicht.

    Bei mir schon. Hast du es bei den Quads auch berichtigt?

    Edit: Ich kann natürlich nicht ausschließen, dass da noch mehr Fehler drin stecken. Aber die Werte sehen nicht völlig kaputt aus.



  • ...an Alle. Jetzt funktioniert es.

    @MFK: Ja, es war die fehlende Berichtigung bei fpQuad.


Anmelden zum Antworten