Wann darf man was aus einer Funktion nicht returnen?


  • Gesperrt

    ... Welche Idiome gibt es, an die man sich halten sollte? (Ernstgemeinte Frage, bitte beantworten)

    Soweit ich weiß, können int s, struct s und Arraypointer problemlos returned werden, aber was sollte man vermeiden? Welche Anti-Pattern gibt es? Danke



  • @EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Arraypointer

    Was soll das sein?

    Du darfst nichts zurückgeben, was irgendwie lokale Variablen referenziert.


  • Gesperrt

    Wie gesagt, die Frage ist ernstgemeint. Demzufolge würde ich mich auch über ernste Antworten freuen. Wer seine schlechte Laune an andere rauslassen muss, sollte sich nen Boxsack aufstellen, um sich erst mal abzureagieren.

    A_Elem search_max(int *const a, const int count)
    {
        A_Elem ae;
        int i = 0;
        int max_index = 0;
        for (; i < count; i++)
        {
            if (a[i] > a[max_index])
            {
                max_index = i;
            }
        }
        ae.max_index = max_index;
        ae.max = a[max_index];
        ae.maxp = &a[max_index];
        return ae;
    }
    

    Wieso darf ich hier dann ae returnen?



  • @EinNutzer0
    Warum solltest Du das nicht dürfen?



  • Als Kopie kannst Du alles zurückgeben wie Du lustig bist. Einen Zeiger oder eine Referenz nur, wenn das referenzierte Objekt eine Lebenszeit hat die nicht an die Funktion gebunden ist. Zeiger/Referenz auf funktionslokale Objekte: nein.



  • @EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Wer seine schlechte Laune an andere rauslassen muss, sollte sich nen Boxsack aufstellen,

    Hast du einen Knall?



  • @EinNutzer0 Bezüglich der Antwort von @manni66 ... Wenn Du schwabbelige Begriffe wie "Arraypointer" verwendest musst Du Dir die Nachfrage nach deren Bedeutung schon gefallen lassen. Da war nichts unsachliches oder gar persönliches.


  • Mod

    Ich nehme mal an, die Frage ist hierdurch ausgelöst worden:

    @SeppJ sagte in Höchsten Zahlenwert im Array suchen.:

    @EinNutzer0 sagte in Höchsten Zahlenwert im Array suchen.:

    Arrr, ich muss genauer fragen, wo war das Problem mit meinem Code?

    Eine Funktion hat gefälligst nie Speicher zu allokieren, den sie nicht selber frei gibt, außer sie ist eine Speicherallokationsfunktion! (Das gilt auch ganz allgemein für jede Art von Ressource: Derjenige, der anfordert, ist persönlich für Freigabe verantwortlich)

    Da muss man zwei Sachen unterscheiden: Dinge, die dir um die Ohren fliegen, weil sie technisch falsch sind, und Dinge, die dir um die Ohren fliegen, weil du dein Programm nicht mehr im Griff hast.

    Zum ersten zählen alle Arten von Dingen, die indirekt auf etwas in deiner Funktion verweisen.

    int *foo()
    {
      int i = 4;
      return &i;
    }
    

    Das explodiert, weil das i nicht mehr existiert nach dem return, und daher der Verweis ungültig wird.
    Weil Arrays in C beim kleinsten Zeichen von Gefahr zu Verweisen auf ihren Anfang werden, gilt das auch für Code in dieser Art:

    int *foo()
    {
      int i[3] = {1,2,3};
      return i;
    }
    

    Das explodiert dir auch sofort. ich spekuliere mal, dass du dies mit "Arraypointer" gemeint hast.

    Der Code in dem anderen Thread, den ich oben zitiert habe, hatte ein anderes Problem, vielleicht noch heimtückischer: Es ist zwar nicht direkt technisch falsch, aber es verhindert mittelfristig, dass du korrekte, komplexe Programme schreiben kannst. Das ist einfach aus der Erfahrung von ~70 Jahren Programmierkunst erwachsen, dass man die Übersicht verlieren wird (kein Konjunktiv!), wenn man gewisse Sachen nicht beachtet. Eine der Sachen ist, dass man stets absolut sicher sein muss, wer die Verantwortung für Ressourcen trägt, und eine gute Faustregel, um das zu garantieren, ist, dass der Verantwortliche stets derjenige ist, der sie belegt hat, und das diese Antwort nicht so einfach wechseln kann. Zumindest nicht unsichtbar bei einem return aus einer Funktion. In abstrakteren Sprachen ist so ein Mechanismus oft sogar in der Sprache eingebaut, aber in C musst du halt selber darauf achten, wenn du dir einen Gefallen tun willst.

    Es gibt natürlich noch jede Menge andere Faustregeln, was als guter Stil gilt, und warum, und was nicht, aber ich kann jetzt nicht einen ganzen Styleguide hier darstellen und erklären.



  • @Swordfish sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Als Kopie kannst Du alles zurückgeben wie Du lustig bist.

    Nicht einen kopierten Zeiger.



  • @SeppJ sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Das explodiert dir auch sofort.

    Wenn er Glück hat, merkt er es (zur Laufzeit).
    Wenn er kein Glück hat, läuft das Programm weiter und der Autor denkt, das Programm läuft fehlerfrei, weil es eben nicht abstürzt.



  • @Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Nicht einen kopierten Zeiger.

    @Wutz

    int foo;
    
    int* bar(void) {
        int *baz = &foo;
        int *qux = baz;
        return qux;
    }
    

    und nu?



  • @EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Wie gesagt, die Frage ist ernstgemeint. Demzufolge würde ich mich auch über ernste Antworten freuen. Wer seine schlechte Laune an andere rauslassen muss, sollte sich nen Boxsack aufstellen, um sich erst mal abzureagieren.
    A_Elem search_max(int *const a, const int count)
    {
    A_Elem ae;
    int i = 0;
    int max_index = 0;
    for (; i < count; i++)
    {
    if (a[i] > a[max_index])
    {
    max_index = i;
    }
    }
    ae.max_index = max_index;
    ae.max = a[max_index];
    ae.maxp = &a[max_index];
    return ae;
    }

    Wieso darf ich hier dann ae returnen?

    Weil hier eine Strukturvariable beim return kopiert wird darfst du das machen.
    Wenn die Strukturelemente auch alle Kopien sind und ausschließlich nichtfunktionslokale Daten referenzieren, darfst du sogar mit der Strukturkopie nach Funktionsaufruf unfallfrei weitermachen.



  • @Swordfish
    Deine Aussage - es muss nur eine Kopie sein und alles wird gut - ist pauschal und somit falsch.
    Und dir ein entsprechendes Beispiel zu präsentieren, spare ich mir jetzt mal.



  • Na dann verallgemeinern wir doch weiter. C kennt sowieso keine Referenzen. Was zurückgegeben wird muss (zumindest sollte) danach ein gültiger Wert sein. Ein Zeiger auf ein Objekt dessen Lebenszeit um ist ist es nicht.


  • Gesperrt

    @SeppJ sagte in Wann darf man was aus einer Funktion nicht returnen?:

    ich spekuliere mal, dass du dies mit "Arraypointer" gemeint hast.

    ja. Arraypointer == ein Pointer auf das erste Arrayelement

    Aber ich versteh's nicht, wieso ich ae returnen DARF. Die Variable ae wird doch nach dem Verlassen von search_max weggeräumt.


  • Gesperrt

    @Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Weil hier eine Strukturvariable beim return kopiert wird darfst du das machen.

    Also doch Call By Value Result... 😊

    Es wird also zweimal eine Kopie erstellt, beim Aufruf und bei der Rückkehr. Wobei eine Kopie einer struct die gesamte struct ist... right?



  • @EinNutzer0
    Wo wird beim Aufruf eine Kopie erstellt? Nirgends.
    Jede Zuweisung einer Struktur impliziert eine Kopie aller seiner Elemente (außer FAM - ja wer weiß das schon? - naja es reicht ja, wenn ich das weiß).

    Und passend dazu ein Zitat des allwissenden (Vorsicht Ironie) Fachbuchautors Jürgen Wolf (Pfuscher JW) aus "C von A bis Z":

    Folgende Wertzuweisung von Strukturen sollten Sie allerdings vermeiden:

    struct {
       int a1;
       int a2;
       int a3;
    } werte1, werte2;
    
    werte1.a1 = 8;
    werte1.a2 = 16;
    werte1.a3 = 32;
    
    werte2 = werte1;   // Bitte vermeiden Sie solche Zuweisungen.
    

    Das ist in C zwar erlaubt, kann aber zu Fehlern führen, wenn ein Compiler dies nicht unterstützt. Sicherer wäre die folgende Möglichkeit:

    memcpy(&werte2, &wert1, sizeof(werte1));
    

    Zitat Ende.
    Pfuscher JW impliziert hier also, dass ein C-Compilerbauer keine Ahnung vom Standard hat und nicht weiß, wie er solche "komplizierte" Regel fehlerfrei umsetzen soll.

    Ich hoffe, das nimmt dir zukünftig die Laune, C anhand von Büchern,Tutorials,Professoren zu erlernen.

    A_Elem search_max(int *const a, const int count)
    

    Hier ist const komplett überflüssig und suggeriert somit Falsches.



  • @Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:

    außer FAM - ja wer weiß das schon? - naja es reicht ja, wenn ich das weiß

    Für alle die sich fragen: Flexible Array Members. Der Größe bezüglich offene Array am Ende einer Struct. Der Benutzer ist dafür zuständig genügend Speicherplatz für eine Objekt einer solchen Struct zu beschaffen.


    @EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Also doch Call By Value Result...

    Würdest Du bitte mal im Bezug auf die Sprache C mit Calling Conventions aufhören?? Lies den Standard und sag' bescheid wenn Du etwas dazu findest. Viel Glück.


  • Gesperrt

    @Wutz sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Wo wird beim Aufruf eine Kopie erstellt? Nirgends

    Das stimmt nicht, Aktualparameter werden durch Zuweisung an die Formalparameter kopiert.

    Es wäre aber schön zu wissen, was genau bei einer Zuweisung geschieht. Ich muss mir mal den Disassembler anschauen, befürchte ich.



  • Und

    @EinNutzer0 sagte in Wann darf man was aus einer Funktion nicht returnen?:

    Call By Value Result

    in C schonmal garnie-nicht.

    Call By Value Result:

    A ParameterPassing mode, used in AdaLanguage to handle "IN OUT" parameters. In CallByValueResult, the actual parameter supplied by the caller is copied into the callee's formal parameter; the function is run; and the (possibly modified) formal parameter is then copied back to the caller.

    nix "return".


Anmelden zum Antworten