x
is local variable and should go out of scope after an execution of fun()
is
over.
Its address is made available via a returned pointer and a global pointer p
, which points to something which is not valid anymore. But still, output printed is 5
.
Why?
#include <stdio.h>
int *p = NULL;
int *fun() {
int x = 5;
p = &x;
return p;
}
// Driver Code
int main() {
printf("%d", *(fun()));
return 0;
}
Local variables are allocated in the stack. When you call fun() from main() the stack appears as something like:
+---------------+ <---- Stack pointer
| local var x |
+---------------+ <---- Address of 'x'
| Return addr |
| in main() |
+---------------+
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
When you go back to main(), the local variables, returned address and parameters are popped from the stack. But the stack is not cleared (by the way, it would consume too much CPU!). So, only the stack pointer moves:
+---------------+
| local var x |
+---------------+ <---- Address of 'x'
| Return addr |
| in main() |
+---------------+ <---- Stack pointer moved with the pops
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
Everything which is above the stack pointer is considered invalid even if it is not cleared. So, it is why that you are lucky enough to get the value of x
in the main() function.
But let's say that you call another function right after fun():
#include<stdio.h>
#include<string.h>
int *p = NULL;
void fun2()
{
int var = 18;
int var2 = 43;
printf("fun2() called, var@%p=%d, var2@%p=%d\n", &var, var, &var2, var2);
}
int *fun()
{
int x = 5;
p= &x;
return p;
}
// Driver Code
int main(int argc, char *argv[])
{
int *px;
px = fun();
printf("x@%p=%d\n", px, *px);
if (argc != 1) {
fun2();
}
printf("x@%p=%d\n", px, *px);
return 0;
}
When the program does not call fun2(), it behaves as yours but I added the display of the address of x
:
$ gcc try.c -o try
$ ./try
x@0x7ffd5beb5f04=5
When the program is passed any parameter, we call fun2() after fun() and we display x
before and after the call to fun2():
$ ./try any_param
x@0x7ffeadacc084=5
fun2() called, var@0x7ffeadacc080=18, var2@0x7ffeadacc084=43
x@0x7ffeadacc084=43
We can see that the value of x
is changed to 43 after the call to fun2() because, the local variable var2
in fun2() has been put at the same place as x
when fun() was running. Hence, the same address 0x7ffeadacc084
in the stack and of course the new value 43 of x
which is in fact the value of var2
.
Here is how the stack looks like after calling fun2() (the former data of _fun() have been overwritten by the data of fun2()):
+---------------+
|local var var |
+---------------+ <---- Address of 'var' = 0x7ffeadacc080
|local var var2 |
+---------------+ <---- Address of 'var2' = 0x7ffeadacc084
| Return addr |
| in main() |
+---------------+ <---- Stack pointer moved with the pops
|Local vars of |
| main() |
+---------------+
| ... |
+---------------+
PS: The stack grows from the high to low addresses. Hence, var
is located at an address lower than the address of var2
.