Zeiger als Rückgabewert einer Funktion zeigt auf 'Funktionsvariable'



  • Hallo liebe C-Gemeinde 🙂

    ich bin Anfänger in Sachen C, arbeite mich gerade durch das Buch "C von A bis Z" von Jürgen Wolf und habe ein Frage zum Kapitel 14.6.1 das Zeiger als Rückgabewert von Funktionen behandelt.

    Genauer gesagt habe ich zu folgendem Programmfragment eine Frage:

    char *test4(char *ptr){
       char buffer[10];
       ptr = buffer;
       strcpy(buffer, "testwert");
       return ptr;
    }
    

    Problem:
    Nach meinem Verständnis wird der Zeiger zwar zurückgegeben und zeigt auf die Adresse von buffer (genauer: auf die Adresse von buffer[0]), der Adressbereich von buffer ist aber nach Abarbeitung der Funktion test4() nicht mehr - wie soll ich sagen - geschützt.

    Frage:
    Könnte es nicht theoretisch passieren, dass im späteren Programmverlauf eine neue Variable deklariert wird, deren Adressbereich den der (früheren) buffer-Variable zumindest teilweise überlagert?

    Ist der Adressbereich von buffer nach der Abarbeitung von test4() noch in irgendeiner Weise geschützt? Lebt buffer gar weiter, weil ptr darauf zeigt?

    Habe ich was nicht richtig verstanden?

    Ich wäre euch dankbar, wenn ihr Licht ins Dunkel bringen könntet 😉

    Gruß
    Robert



  • robert schrieb:

    Könnte es nicht theoretisch passieren, dass im späteren Programmverlauf eine neue Variable deklariert wird, deren Adressbereich den der (früheren) buffer-Variable zumindest teilweise überlagert?

    => Ja. Spätestens beim Aufruf der nächsten Funktion. Allerdings: Deklaration einer weiteren Variablen (z.B. in einem nachfolgenden Block) ist unproblematisch. Variable ist im Stack angelegt, mit Aufruf einer nächsten Funktion wird der Stack wieder überschrieben. Es gibt aber auch (seltene) Möglichkeiten, wo der Stack auch ohne Aufruf einer weiteren Funktion überschrieben wird (s.u.).

    robert schrieb:

    Ist der Adressbereich von buffer nach der Abarbeitung von test4() noch in irgendeiner Weise geschützt? Lebt buffer gar weiter, weil ptr darauf zeigt?

    => "buffer" liegt im Stack, ist nach Rückkehr aus der Funktion als nicht mehr zugreifbar zu betrachten. "buffer" lebt nicht weiter, nur weil ein anderer Pointer drauf zeigt.

    P.S.: Man kann auch nicht nach Rückkehr aus der Funktion den Inhalt des Pointers zu Fuß (z.B. mittels einer Schleife) umkopieren, denn nach Rückkehr aus der Funktion kann der zu "buffer" gehörende Stackbereich zu einem beliebigen Zeitpunkt nicht mehr gültig sein (Siehe hierzu ggf. auch meine diversen Anmerkungen im Thread http://www.c-plusplus.net/forum/viewtopic-var-t-is-155098-and-postdays-is-0-and-postorder-is-asc-and-start-is-10.html, wo jemand vorgeschlagen hat, nach einem Funktionsaufruf nachträglich den Stack auszuwerten.

    P.P.S.: Etwas anderes ist es, wenn man definiert:

    static char buffer[10];
    

    Ist zwar nicht die feine Art, kann aber unter gewissen Rahmenbedingungen und bei gewissen Anwendungen als legitim gelten. Mit dem Zusatz "static" wird nämlich Speicherplatz im globalen Memory-Bereich vorgesehen (bei häufiger Anwendung wird aber hierdurch unnötig viel Speicherplatz verbraucht).



  • Das Problem könnte man auch lösen, indem man statt des char[ 10 ] buffers in test4( ) den Speicher dynamisch anfordert:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    char* test4( char **ptr )
    {
        *ptr = malloc( 10 );
    
        if( !( *ptr ) )
            return 0;
    
        strcpy( *ptr, "testwert" );
    
        return *ptr;
    }
    
    int main( )
    {
        char *ptr;
        if( test4( &ptr ) ) {
    
            puts( ptr );
            free( ptr );
    
        } else {
    
            puts( "Not enough memory!" );
            return EXIT_FAILURE;
        }
    }
    

    Greetz, Swordfish



  • Swordfish schrieb:

    if( !( *ptr ) )
    

    Nana da ist aber ein Sternchen zu viel!



  • kenner: ueberleg nochmal. die bedingung kommt nach dem malloc(), also testet sie den erfolg von malloc().
    waere ptr vor dem malloc() schon NULL, wuerde das ding eh crashen.



  • Ops ich dachte das sei nur ein char*, ist ja ein char**. Sry mein Fehler.



  • Kenner... schrieb:

    Ops ich dachte das sei nur ein char*, ist ja ein char**. Sry mein Fehler.

    Blinde Nuss! 😃

    Greetz, Swordfish



  • Ich hatte zu dem gleichen Problem die Frage, kannst du hier nachlesen.
    Entweder du legst die Variable buffer als static an, du allozierst Dynamischen Speicher (Kp.16).


Anmelden zum Antworten