Return a pointer that points to a local variable [duplicate]
I don't know why this works. Since x is a local variable, I thought I would get an error when I try to return it. However, The first printf works fine, but then it just prints out 0. Can anyone explain what's going on here?
#include <stdio.h>
int* func1() {
int x = 123123;
int *y = &x;
return y;
}
int main()
{
int* c = func1();
printf("%d\n", *c); // output: 123123
printf("%d\n", *c); // output: 0
return 0;
}
The following happens:
- Within
func1
, you created the localx
variable and initialised it with a value, i.e.x
is on the stack now. - You get the address of
x
and return it tomain
. - While returning,
func1
and its variablesx
(and, irrelevant to the question,y
) arefree
d, or popped off the stack, i.e. their memory locations are not reserved any more to hold their values. After this, any other part of the program is allowed to use the memory space that was allocated forx
withinfunc1
, asfunc1
isn't active any more. - Your first
printf
call still happens to see the old value of the memory location wherex
used to be (but this is not guaranteed) and - the second
printf
call makes it apparent that something else (with the value of 0, such as the firstprintf
's return value as described by R. Joiny) is (or was) using the same address asx
withinfunc1
.
This article of the C Programming Boot Camp pretty much describes your situation:
A key to understanding the stack is the notion that when a function exits, all of its variables are popped off of the stack (and hence lost forever). Thus stack variables are local in nature. This is related to a concept we saw earlier known as variable scope, or local vs global variables. A common bug in C programming is attempting to access a variable that was created on the stack inside some function, from a place in your program outside of that function (i.e. after that function has exited).
printf
is basically a function. Like your func1
.
Functions use some RAM, your workspace for local variables. If you leave the function, it becomes assingned as something like "clear for using" (not deleted!).
Because the first printf()
comes directly after the func1()
function, the local variable C is still there, because it's not overwritten yet. So that works. But if you look at this MAN page you can see, that printf has int as a return value. So that has to be written to somewhere, so what would your PC do? Of course write it to the first free adress of the RAM, that is assigned to your program. And there you have your zero.
It's important to notice, that no other program can access your RAM, Windows automatically reserves RAM for every process, so it must be the return value from printf()
(or some other local variable that printf uses while executing).
Since x is a local variable, I thought I would get an error when I try to return it.
A more general answer to this problem is: Wrong code in C code does not necessarily produce a compiler or runtime error.
If you're very lucky, you will get a compiler error or warning.
If you're lucky, you'll get a runtime crash when the wrong code runs (this often happens with null pointer errors). This is easy to track down with a debugger.
But if you're not lucky, wrong code can cause crashes later on (in seemingly unrelated code), or silently corrupt some data structures (making your program behave in weird ways without crashing), or even appear to work fine (until you add seemingly harmless code elsewhere, or use a different compiler, or a different version of the same compiler, or just different compilation options).
Technically your code has undefined behavior at this line:
int* c = func1();
You're using the return value of func1
(writing it into c
). But that value is the address of a local variable in func1
, which no longer exists by the time func
has returned. That means the return value is an invalid pointer, and just using such a pointer leads to undefined behavior (you don't even have to dereference it).
printf("%d\n", *c); // output: 123123
Well, this line both uses the bad pointer (reading it from c
) and dereferences it. The program still appears to work fine.
printf("%d\n", *c); // output: 0
A seemingly harmless addition, but this line doesn't produce the expected output. Now it looks like silent data corruption.
Note that none of this is guaranteed. A different compiler or the same compiler using different optimization settings may well produce code that behaves differently. As far as the standard is concerned, a compiler has to produce code that matches the observable behavior of the C code. But C code whose behavior is undefined can cause anything to happen; there are no guarantees or restrictions on what the compiler can do with it.