4

I'm confused regrading the return of a local variable: the variable, its address and returning address using pointers.

First:

#include <stdio.h>

int returner(void);

int main(void)
{
    printf("The value I got is = %d\n", returner());
    return 0;
}

int returner(void)
{
    int a = 10;
    return a;
}

Output:

The value I got is = 10

The local variable is returned although it should go out of scope after the function returns, how does that work?

Second:

#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    return &a;
}

Output:

Test.c: In function 'returner':
Test.c:15:12: warning: function returns address of local variable [-Wreturn-local-addr]
   15 |     return &a;

Why is the address is not returned, although the value is returned as in First sample?

Third:

#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    int *ptr = &a;
    return ptr;
}

Output:

The value I got is = 10

Now, how is this method returning the address of the local variable and also prints its correct value, although the variable should go out of scope / be destroyed after the function returns?

Please explain the three cases that how the methods are working.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • `int a` -> `static int a` – alex01011 Mar 12 '21 at 17:54
  • 4
    @alex01011 Usage of `static` requires full understanding of what it does. I would not just drop such a suggestion out of context. – Eugene Sh. Mar 12 '21 at 17:55
  • Its not nuclear physics.A simple look up at the documentation and he can understand exactly what it does. – alex01011 Mar 12 '21 at 17:57
  • @alex01011 You would be surprised... I happen to interview many candidates who are supposed to be knowledgeable in C, and this is something that many people just have no idea about. – Eugene Sh. Mar 12 '21 at 17:59
  • @alex01011 I know that `static` variable has lifetime till the end of program. But I don't asked for how we can `return` the address, I asked why the address is not returned in Second but returned in Third!! – Neeraj-Kumar-Coder Mar 12 '21 at 18:00
  • 1
    It's undefined behavior. C does not wipe the values of variables when they go out of scope. – klutt Mar 12 '21 at 18:18
  • It is perfectly valid to return a pointer to a local variable as long as you don't dereference it. Printing the address is not a problem. – stark Mar 12 '21 at 18:23
  • 1
    @stark it actually *is* a problem. As per http://port70.net/~nsz/c/c11/n1570.html#6.2.4: *The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.* – Eugene Sh. Mar 12 '21 at 18:39

4 Answers4

3

In C the return is by value.

The first code returns the value of a, which is 10, and that's fine, it's a mere copy of the local variable a.

The second code returns the value of a pointer to a, which is its address. It just so happens that that address will not be valid after the function goes out of scope, and the lifetime of the local variable stored in that address ends. The compiler is smart enough to detect this and warn you.

The third code is different, there is an assignment of an address coming from another pointer, the compiler doesn't check further to see if the assigned address is valid or not, that extra layer of indirection throws the compiler off.

The output continues to be 10 but this is by chance, it's undefined behavior, and as such, that is one of the possible outcomes. There is no standardized behavior for this kind of construct and to demonstrate it I tweaked things a bit. As you can see here https://godbolt.org/z/eKerdM, with optimizations -O3 enabled.

With clang the program outputs some random value:

The value I got is = -1313555320

And no warnings are produced.

Whereas gcc verifies further and detects a problematic assignment:

<source>: In function 'returner':
<source>:16:12: warning: function returns address of local variable 
[-Wreturn-local-addr]
  16 |     return ptr;
     |            ^~~
<source>:14:9: note: declared here
  14 |     int a = 10;
     |         ^

And the program outputs 0:

The value I got is = 0

In both cases the value is no longer correct, and clang behaves differently from gcc.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
1
  • Output First: the value (which has no scope) is returned.
  • Output Second: You are trying to return the address of something which does go out of scope.
  • Output Third: Although you are trying to do the same thing as previously, the compiler doesn't detect the problem. The pointer being returned, however, is just as problematic.
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
1
int returner(void)
{
    int a = 10;
    return a;
}

The above function returns an int by value, as far as the return goes, it's equivalent to having written return 10;

int *returner(void)
{
    int a = 10;
    return &a;
}

The above is an example of what they call "undefined behavior" - it might work, sometimes, but it's not sound. The address that's returned refers to a position on the function call stack used to provide storage to function local variables. That memory is no longer retained for holding int a after returner returns, although it might not have been reused, and may still have the value 10 at that address, for some time afterward, there is no guarantee.

The third example is not very different from the 2nd. The behavior could differ from the 2nd, as the stack allocation is different, but neither should be expected to work consistently, or to be portable.

0

What's being returned from the function is the value of a, just like what's passed to functions is the value of its parameters.

The only time you would need to worry about going out of scope is when you're returning a pointer to a local function variable with automatic storage duration, i.e.:

int *badFunction ()
{
   int ret[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
   return ret;
}

In this case the value being returned is a pointer to the array ret, however, since ret goes out of scope when badFunction exits, the returned pointer is obviously invalid. Workarounds would be using a variable with static storage duration or the heap.

In your case, with a plain old int, you don't need to worry about scope.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85