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.
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
.