Thread: Return a pointer to a variable declared inside the function (basic question)

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    3

    Return a pointer to a variable declared inside the function (basic question)

    ** sorry, this is a basic question, but couldn't find the answer on Google **

    In the following code, is it guaranteed that the "number" variable will point to the same value as assigned in the "f" function? Because I have the idea that "n" will be destroyed, so "i" will point to a random place, but when I run this code, it prints the right value.

    Code:
    #include <stdio.h>
    
    int *f() {
        int *i;
        int n = 15;
        i = &n;
        return i;
    }
    
    int main() {
        int *number;
        number = f();
        printf("%d", *number);
        return 0;
    }

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Sometimes you get lucky.

    In this case, you got lucky because the computer does not actively destroy information, it merely sets it aside to reuse it. Since you didn't ask for more memory between it getting lost in the call to f and trying to print it, it was still there.

  3. #3
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    you're right, it's not correct.

    You could make it static so that it's the same var whenever you call the function:
    Code:
    #include <stdio.h>
    
    int *f() {
        int *i;
        static int n = 15;
        i = &n;
        return i;
    }
    
    int main() {
        int *number;
        number = f();
        printf("%d", *number);
        return 0;
    }

  4. #4
    Registered User
    Join Date
    May 2008
    Posts
    87
    The way to guarantee the variable will still exist in memory after the function f() has finished executing is to allocate space for it with a call to malloc().

    Code:
    int *f() {
       int *i;     /* declare a pointer to an integer */
       i = malloc(sizeof(int)); /* and assign it the address of a block of memory the
                                         * size of one integer */
       *i = 15;     /* set the value of the integer pointed to by i to 15 */
       return i;      /* return the address of the integer */
    }
    You should also do some error checking. If malloc() fails, it will return NULL and the function above with then have troubles with the *i = 15 line. Also, if you have functions returning pointers to newly allocated spaces in memory, you need to keep track of these places and be sure to free() them when you are done using them. Only use free() on pointers that have been returned by malloc(), otherwise you'll get undefined behavior.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    To answer the original question: no!

    Local (non-static) variables in functions are not guaranteed to exist when the function returns. Returning a pointer to a local variable therefore means the caller receives a dangling pointer (a pointer to something that is not guaranteed to exist). If the caller dereferences that pointer (as you do, in the printf() line) the result is undefined.

    If you get the right results, you've just got lucky (or unlucky if you look at it correctly; you are led to believe the code is correct and it isn't). You are not guaranteed to get the same results with another compiler, an update of your compiler, putting more code into your program, .....

  6. #6
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    When you call a function (in this case f()). You add a new stack frame to the stack, which will contain the return variable, return address, function arguments and local variables. The stack pointer is then advanced by one to this stack frame (f function call) and the code is executed. When you call return, the return value will be set, and the stack pointer decremented and you go back to the calling function (main in this case). The stack frame is not explicitly destroyed. Only if you then called another function, would a new stack frame be pushed on the stack, which would likely overwrite anything that was there previously.
    That's why you should never return anything that's local to a function, it *might* still be there, but you can't rely on it.

    QuantumPete
    Last edited by QuantumPete; 06-09-2008 at 03:47 AM. Reason: too little sleep
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by lecter55 View Post
    ** sorry, this is a basic question, but couldn't find the answer on Google **

    In the following code, is it guaranteed that the "number" variable will point to the same value as assigned in the "f" function? Because I have the idea that "n" will be destroyed, so "i" will point to a random place, but when I run this code, it prints the right value.
    To prove the point that this DOESN'T work, we can do this:
    Code:
    #include <stdio.h>
    
    int *f() {
        int *i;
        int n = 15;
        i = &n;
        return i;
    }
    
    int *g()
    {
        int *p;
        int x = 42;
        p = &x;
        return p;
    }
    
    int main() {
        int *number;
        int *number2;
        number = f();
        number2 = g();
        printf("&#37;d, %d", *number, *number2);
        return 0;
    }
    My guess, is that you will see 42 for both numbers, if it gets any predictable result at all.

    Edit: Fixed up the code to match g() with f() - thanks to QuantumPete for pointing out the bug.
    Last edited by matsp; 06-09-2008 at 04:03 AM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    Quote Originally Posted by matsp View Post
    My guess, is that you will see 42 for both numbers, if it gets any predictable result at all.
    That's interesting, I get 15 and 42 printed out...

    QuantumPete

    Edit: and I see why, x in g() overwrites i in f(), which only hold the address of n, which is therefore still alive and kicking on the stack. After that call to printf, however, the values get scrambled.
    Last edited by QuantumPete; 06-09-2008 at 04:00 AM.
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > That's interesting, I get 15 and 42 printed out...
    My guess is you're using gcc
    Quote Originally Posted by gcc manual
    -fno-defer-pop
    Always pop the arguments to each function call as soon as that function returns. For machines which must pop arguments after a function call, the compiler normally lets arguments accumulate on the stack for several function calls and pops them all at once.

    Disabled at levels -O, -O2, -O3, -Os.
    If defer-pop is enabled, then your variable, which has gone out of scope, can last a bit longer than you might otherwise suspect.

    Just goes to show you that it's impossible to get a consistent answer out of UB
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Salem View Post
    > That's interesting, I get 15 and 42 printed out...
    My guess is you're using gcc

    If defer-pop is enabled, then your variable, which has gone out of scope, can last a bit longer than you might otherwise suspect.

    Just goes to show you that it's impossible to get a consistent answer out of UB
    But defer-pop only applies to function arguments, not local variables within functions - it may however, well be that if optimization is sufficiently applied, it inlines both f() and g() into main() and allows both sets of variables to exist at once - it shouldn't use twice the stack-space. I think Quantumpete will agree that the updated [after QP's post] code "works" in the "correct broken" way - but I don't say that all compilers will manage to do this right without doing something different - and there's a high probability that printf itself uses the same piece of memory too, so there's no guarantee that either 15 or 42 is being printed, actually.

    Edit: To prove the point:
    Code:
    D:\temp>gcc -Wall ub.c
    
    D:\temp>a
    42, 42
    D:\temp>gcc -Wall -O2 ub.c
    
    D:\temp>a
    16384, 16384
    D:\temp>gcc -Wall -O3 ub.c
    
    D:\temp>a
    15, 42
    Three different results for the same code, depending on which compiler option. Another compiler will probably give another set of answers (at least on the second variant). The compiler is gcc-mingw 3.4.2
    --
    Mats
    Last edited by matsp; 06-09-2008 at 09:59 AM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Troubleshooting Input Function
    By SiliconHobo in forum C Programming
    Replies: 14
    Last Post: 12-05-2007, 07:18 AM
  2. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  3. Calling a Thread with a Function Pointer.
    By ScrollMaster in forum Windows Programming
    Replies: 6
    Last Post: 06-10-2006, 08:56 AM
  4. I need help to compile this code...
    By wise_ron in forum C Programming
    Replies: 17
    Last Post: 05-07-2006, 12:22 PM
  5. C++ FTP class won't work
    By lord mazdak in forum C++ Programming
    Replies: 8
    Last Post: 12-18-2005, 07:57 AM