call-by-reference & funktion mit zeiger als rückgabewert



  • knobel grade an funktionen in verbindung mit zeigern und hab
    mal ein kleines programm geschrieben um die oben genannten konzepte
    zu testen.

    Frage:
    Wieso kann hier einer nicht-pointer variable (erg) ein pointer (return press) zugeordnet werden???

    #include <stdio.h>
    #include <stdlib.h>
    /* ANWENDUNG VON CALL-BY-REFERENCE UND FUNKTION MIT ZEIGER ALS RÜCKGBEWERT*/
    
    int *sqr(int *base) { //funktion um das quadrat zu berechnen
       int res;
       int *pres=&res; 
    
       res = (*base)*(*base); 
    
       return pres;   
    }
    
    int main(void) {
       int basis;
       int erg;
       printf("enter base");
       scanf("%d", &basis);
       erg = *sqr(&basis); // wieso kann hier einer nicht-pointer variable (erg) ein pointer (return press) zugeordnet werden???
       printf("result : %d",erg); 
       return EXIT_SUCCESS;
    }
    

    noob bittet um antwort ^^

    grüße,
    s.


  • Mod

    Weil *sqr kein Pointer mehr ist, da du ihn mit dem Stern dereferenziert hast.

    An deinem Programm ist so ziemlich alles falsch, was man mit Pointern falsch machen kann. Hast du einfach so lange zufällige '*' und '&' im Code verteilt, bis es compilierte? Compilieren != Richtig! Und Ausprobieren != Programmieren! Versuch dringend erst einmal die Grundlagen aus einem guten(!) Lehrwerk zu lernen, bevor du wild rumprobierst.



  • In der deklarativen Phase, also in Zusammenhang mit einem Typ bedeutet '*' immer Zeigerdeklaration/definition, anderweitig Dereferenzierung.

    int *sqr(int *base) { /*Funktion, die int-Zeiger zurückliefert und int-Zeiger als Parameter besitzt */
    int *pres=&res; /* Definition int-Zeiger, initialisiert mit Adresse einer lokalen Variable */
    
    res = (*base)*(*base); /* Daten(=Wert), auf die der Zeiger base zeigt == Dereferenzierung */
    

    In C gibt es nur call-by-value, das oftmals genannte call-by-reference via Zeiger ist immer auch nur ein call-by-value, da der Wert kopiert wird und nicht der Zeiger selbst durchgereicht wird.



  • Hi und danke für die schnellen antworten!

    Also dereferenziert der * vor dem funktionsnamen den rückgabewert?

    int *sqr(int *base)
    

    @sepp
    klar ist das total chaotisch und macht wenig sinn, mir ging es auch nicht darum
    ein besonders effinzientes/sinvolles programm zu schreiben, sondern erstmal die sache mit pointern als rückgabewert "auszuprobieren".
    Trotzdem ist das Programm natürlich absolut hässlich ^^.

    @wutz
    danke, so hab ich das auch verstanden.
    aber wenn du schreibst

    int *sqr(int *base) { /*Funktion, [b]die int-Zeiger zurückliefert[/b]...
    

    frag ich mich wieder, wieso der int-zeiger "pres" in "erg" gespeichert werden kann...oder dereferenziert * vor der funktion bereits wieder den pointer?

    p.s.
    wenn nicht wirklich zeiger übergeben werden, gibt es also keinen geschwindigkeitsvorteil durch zeiger 😕


  • Mod

    S3raph1m. schrieb:

    Hi und danke für die schnellen antworten!

    Also dereferenziert der * vor dem funktionsnamen den rückgabewert?

    int *sqr(int *base)
    

    Nein, dies ist eine Funktionsdeklaration (oder der Anfang einer Definition, kann man hier nicht sagen), die besagt, dass sqr einen Zeiger auf int zurück gibt.

    Wenn du später

    int erg = *sqr(&basis);
    

    machst, dann liefert sqr(&basis) einen Zeiger auf einen int. Aber das Sternchen dereferenziert den Zeiger und man bekommt den int auf den er zeigt.

    @sepp
    klar ist das total chaotisch und macht wenig sinn, mir ging es auch nicht darum
    ein besonders effinzientes/sinvolles programm zu schreiben, sondern erstmal die sache mit pointern als rückgabewert "auszuprobieren".
    Trotzdem ist das Programm natürlich absolut hässlich ^^.

    Du verstehst nicht. Ich meine nicht falsch wie in "hässlich", "umständlich" und "sinnlos". Ja, es ist auch hässlich, umständlich und sinnlos. Aber es ist auch falsch wie in falsch. Und zwar einmal falsch im Sinne der Aufgabenstellung und einmal falsch im Sinne von technisch falsch. Aufgabenstellung: Du machst hier kein call by reference in dem Sinne wie es gemeint ist und hast das Konzept offenbar auch nicht verstanden. Technisch falsch gibst du einen Zeiger auf ein lokales Objekt zurück und dereferenzierst diesen, nachdem das Objekt nicht mehr existiert. Undefiniertes Verhalten. Klingt harmlos, ist es aber nicht. Kann manchmal funktionieren, wenn man Pech hat. Dann merkt man es nicht. Ist aber trotzdem falsch und wird nach Murphy bei der ungünstigsten Gelegenheit zu einem Fehler führen.

    p.s.
    wenn nicht wirklich zeiger übergeben werden, gibt es also keinen geschwindigkeitsvorteil durch zeiger 😕

    Häh? Lern erst einmal C bevor du optimierst. Dann verstehst du auch, warum manchmal Zeiger schneller sein können.



  • Wutz schrieb:

    In C gibt es nur call-by-value, das oftmals genannte call-by-reference via Zeiger ist immer auch nur ein call-by-value, da der Wert kopiert wird und nicht der Zeiger selbst durchgereicht wird.

    Irgendwie wird mir nicht klar, was Du hiermit ausdrücken willst.

    call-by-reference meint doch, dass das Unterprogramm keine Kopie des Variablenwertes sondern eine Kopie des Variablenzeigers (auf den Variablenwert) erhält.

    Ciao, Allesquatsch



  • Allesquatsch schrieb:

    Wutz schrieb:

    In C gibt es nur call-by-value, das oftmals genannte call-by-reference via Zeiger ist immer auch nur ein call-by-value, da der Wert kopiert wird und nicht der Zeiger selbst durchgereicht wird.

    Irgendwie wird mir nicht klar, was Du hiermit ausdrücken willst.

    call-by-reference meint doch, dass das Unterprogramm keine Kopie des Variablenwertes sondern eine Kopie des Variablenzeigers (auf den Variablenwert) erhält.

    Das ist halt Definitionssache. Ich sehe das auch so, dass eine indirekte Übergabe eines Wertes über einen Zeiger selbstverständlich call-by-reference ist. Dabei finde ich völlig irrelevant, dass die Adresse selbst als Wert übergeben wird, wie es in anderen Sprachen unter der Haube sicher auch ist.



  • @sepp
    erstmal danke, dass du dich trozt meiner unwissenheit überhaupt mit meinen postings beschäftigst ^^.

    1.ahh okay, ich denke ich habe diesen einen fehler verstanden.
    ich habe nicht erkannt das * ja ein ein teil der deklaration ist.

    2.möglicherweise habe ich call-by-reference nicht verstanden.
    mein gedanke war es die adresse einer lokalen variable von main() an eine funktion zu übergeben, die diese dereferenziert und mit dem wert arbeitet.
    ich werde mich nochmal eingehender damit befassen.

    3.ich ahne was du mit

    "Technisch falsch gibst du einen Zeiger auf ein lokales Objekt zurück und dereferenzierst diesen, nachdem das Objekt nicht mehr existiert."

    meinst.

    da die funktion einen zeiger auf ein lokales objekt der funktion zurückgibt und diese dann terminiert wird, existiert das objekt dann auch nicht mehr.
    dann hab ich das thema "funktion mit zeiger als rückgabewert" wohl noch überhaupt nicht begriffen ^^.

    4.mir ist schon bewusst wieso zeiger "schneller" sein sollten
    als das kopieren von variablenwerten. allerdings habe ich mich mit meinem "p.s." über wutzs äußerung gewundert, dass es in c kein call-by-reference gäbe.

    danke für die hilfe,
    s.


  • Mod

    S3raph1m. schrieb:

    2.möglicherweise habe ich call-by-reference nicht verstanden.
    mein gedanke war es die adresse einer lokalen variable von main() an eine funktion zu übergeben, die diese dereferenziert und mit dem wert arbeitet.
    ich werde mich nochmal eingehender damit befassen.

    Das ist schon richtig, aber normalerweise (außer bei geschwindigkeitsoptimierungen) ist der Sinn dahinter, dass man den Wert auch tatsächlich ändert. Die aufgabenstellung will sicherlich, dass du basis einliest und nach sqr(&basis) soll der Wert von Basis quadriert sein.

    3.ich ahne was du mit

    "Technisch falsch gibst du einen Zeiger auf ein lokales Objekt zurück und dereferenzierst diesen, nachdem das Objekt nicht mehr existiert."

    meinst.

    da die funktion einen zeiger auf ein lokales objekt der funktion zurückgibt und diese dann terminiert wird, existiert das objekt dann auch nicht mehr.
    dann hab ich das thema "funktion mit zeiger als rückgabewert" wohl noch überhaupt nicht begriffen ^^.

    Zeiger als Rückgabewert sind selten richtig. Siehe Antwort auf Punkt 2, wie wolh gedacht ist, dass du das Ergebnis aus der Funktion heraus bekommt.

    4.mir ist schon bewusst wieso zeiger "schneller" sein sollten
    als das kopieren von variablenwerten. allerdings habe ich mich mit meinem "p.s." über wutzs äußerung gewundert, dass es in c kein call-by-reference gäbe.
    s.

    Er meint damit, dass C nicht direkt call-by-reference als Sprachmittel unterstützt. Der Pointer wird als Kopie übergeben und darüber hat man sich dann indirekt den gleichen Effekt wie call-by-reference für das Objekt auf das der Zeiger zeigt gebastelt. Man darf aber nicht dem Irrtum verfallen, dass der Pointer hier das Signal für ein call-by-reference im Sinne anderer Sprachen (wie Pascal oder C++) ist. Hier kommen andauernd Leute, die einen Pointer by-reference übergeben wollen und nicht kapiert haben, wie das richtig geht.



  • S3raph1m. schrieb:

    4.mir ist schon bewusst wieso zeiger "schneller" sein sollten
    als das kopieren von variablenwerten.

    Schnelligkeit ist gar nicht das Hauptargument, obwohl es auch dafür gezielt eingesetzt wird. Viel wichtiger ist das Prinzip der Referenzparameter aber für die Speichereffizienz und Abstrahierung.

    Funktionen, die mit Strings oder anderen Arrays arbeiten, müssten sich sonst selbst um die Speicherallokation kümmern und darüber Annahmen treffen. Dann müsste beim Aufruf und bei der Rückgabe eifrig hin- und herkopiert werden.

    Zudem bleibt alles immer an der selben Stelle: Referenzen, die in einem Unterprogramm gesetzt werden, verweisen auch noch nach dem Verlassen auf das selbe Objekt.

    Und die Pointergeschichte funktioniert halt mir wesentlich mehr als nur "dummen" Datenstrukturen sondern auch mit Funktionen, Dateistreams usw.

    S3raph1m. schrieb:

    allerdings habe ich mich mit meinem "p.s." über wutzs äußerung gewundert, dass es in c kein call-by-reference gäbe.

    Die Verwirrung war auch bei mir, liegt aber eher daran, wie man die Begriffe genau verwendet. Vielleicht liegt es daran, dass man bei C quasi unter die Motorhaube schauen kann und sieht, dass hier die Übergabe über Werteübergabe von Pointern gemacht wird.

    Ciao, Allesquatsch



  • Danke nochmal für die ausführlichen antworten!

    Ich wollte nur nochmal klarstellen, dass dies KEINE aufgabenstellung von irgendeiner lehranstalt oder sonstwas ist, sondern reines "privatvergnügen" und beschäftigungstherapie, da ich momentan nicht das haus verlassen kann 🙂 .

    MfG,
    M.T.


Anmelden zum Antworten