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.

8
  • int a -> static int a Commented Mar 12, 2021 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. Commented Mar 12, 2021 at 17:55
  • Its not nuclear physics.A simple look up at the documentation and he can understand exactly what it does. Commented Mar 12, 2021 at 17:57
  • 1
    It's undefined behavior. C does not wipe the values of variables when they go out of scope. Commented Mar 12, 2021 at 18:18
  • 1
    @stark it actually is a problem. As per 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. Commented Mar 12, 2021 at 18:39

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.