Correct. Do not use references for variables that are on the function's local stack.
When you enter a function C sets up a stack. If you have parameters those are popped off of the stack and used. If you declare a variable inside of the function and attempt to return a reference to that variable, you will have major problems
Code:
int MyFunc(void)
{
int i=0;
return i;
}
This is ok because the value of i is returned, not the address of i.
What MyFunc might look like in assembly (NASM):
Code:
MyFunc:
push ebp //save base pointer
mov esp,ebp //set stack pointer to base
sub esp,4 //subtract 4 for int -> int i=0;
mov [esp-4],0 //set i to 0, i is at esp-4
mov eax,[esp-4] //mov value of 0 to esp-4 or i to return value to C
add esp,4 //Erase i by adding 4 to stack pointer
pop ebp //Restore base pointer
ret //return to caller
So if you were to return a reference to i, it no longer exists. But if you return the value of i, the compiler moves the value at [esp-4] or where 'i' is into eax - in C all integral returns are returned in EAX and all floating point return values are in ST(0).
So you see the add esp,4 and pop ebp effectively erase i and its address. It no longer exists. Future functions will use the stack and alter what we called 'i'.
Stack on entry to MyFunc
---------------> top of stack on entry
previous value of EBP
caller address
function parameters
Then when we declare integer 'i' which takes 4 bytes in 32-bit code - we reserve 4 bytes above the current stack pointer for this:
Stack after declaring variable 'i'
[esp-4] 'i' -----> 4 bytes above the top of the stack
-----------------> top of stack on entry
previous value of EBP
caller address
function parameters
....
....
And this on exit from MyFunc (after the parameters are popped off of the stack or removed):
Stack on exit from MyFunc
(previous position of variable i)
----------------> top of stack on exit
previous value of EBP
caller address
(parameters -> are popped off before returning to caller)
So if you return a reference to where i was, you will have major issues in your code because 'i' does not exist anymore.
Also you will note that the pop ebp will pop the first or top item off of the stack which just happens to be the previous address of EBP - so EBP is restored to what it was on entry. Then the RET will return to the caller - essentially - the actual nitty gritty of the RET instruction takes about 3 pages in the Intel manuals.