2

Possible Duplicate:
Can a local variable's memory be accessed outside its scope?

today i attended a seminar on basic C coding and we stumbled upon a brainteaser, that none of the present assistants could answer me to my content.

the code is:

#include <studio.h>

int *f(int a) {
    int b = 2 * a;
    return &b;
}


int main(void) {
    int *p4;
    int *p8;
    p4 = f(4);
    p8 = f(8);
    printf("p4: %i / p8: %i\n", *p4, *p8);
}

i know what is wrong with the code and i would never myself code something like that, but it is still interesting.

the output is:

p4:16 / p8:16

intended was of course

p4:8 / p8:16

what i first expected was that we'd get an error because after the functon f is through &b should not exist anymore (variable scope).

the assistants explained it as 'lucky punch' that there is still something in the memory at that position, but that did not really do it for me.

i thought id post it here and see if someone has a better explanation.

IMPORTANT: this is not a question of how to add 2 ints in a function - i am fairly capable of that - its: why is the number 16 stored at *p4 when retrieving it for the printf.

looking forward to inspiring answers, sebastian

Community
  • 1
  • 1
Sebastian Flückiger
  • 5,525
  • 8
  • 33
  • 69
  • 2
    Is that `#include` line valid? – Blender Mar 09 '12 at 20:24
  • The `` on the very first code line is a typo? – Basile Starynkevitch Mar 09 '12 at 20:25
  • 3
    You are dereferencing an uninitialized local pointer e.g. `p4`. This is **undefined behavior** so anything can happen according to the standard (e.g. your computer could explode, or print anything). – Basile Starynkevitch Mar 09 '12 at 20:28
  • 4
    Undefined behavior can behave in *any way the compiler wants*. Attempting to rationalize a particular compiler's choice is probably not worth the effort. – Mark B Mar 09 '12 at 20:28
  • @james mcNellis: thanks for the great link - i'ts getting clear to me that it actually is luck (or however to call it) that it is still there. but why is the same for both *p4 and *p8? shouldnt *f() use new adresses for the two calls to store b? – Sebastian Flückiger Mar 09 '12 at 20:30
  • This program could play your favorite Beethoven symphony and still be compliant to the standard. – Alexandre C. Mar 09 '12 at 20:35
  • thanks you guys for adding the duplicate link =) my question is answered. but really interesting on how not defining something can cause headache =) – Sebastian Flückiger Mar 09 '12 at 20:37
  • 2
    @Sebastian Flückiger: Since &b is returned and b is stored on f, chances are that the same stack address is used if you call f twice without doing anything else in between. This means p4 and p8 point to the same memory, with 16 being written to it last. Nothing you should rely on, but probably what is happening in this case. – Leo Mar 09 '12 at 20:38

2 Answers2

5

why is the number 16 stored at *p4 when retrieving it for the printf.

With undefined behavior - anything can happen.

int *f(int a) {
    int b = 2 * a;
    return &b;
}

You are returning a pointer to a variable that is destroyed, and then you access that memory location. That is the UB.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • For a newbie (and even for many C developers) there is a lesson here: **always initialize local pointers to `NULL`** (if the original poster asked that, he would got a SIGSEGV and won't bother to ask, and just use the debugger). – Basile Starynkevitch Mar 09 '12 at 20:41
  • @BasileStarynkevitch: What does that have to do with anything? (Perhaps you're looking at the old version of his code?) – GManNickG Mar 09 '12 at 21:28
  • I was talking of `p4` and `p8` in original question, not in your answer. – Basile Starynkevitch Mar 09 '12 at 21:46
  • @basile: yes youre right but it has nothing to do with my question :-) as i pointed out the question was not what is wrong with the code (that i know myself) but why it behaves the way it does. – Sebastian Flückiger Mar 10 '12 at 09:41
  • @SebastianFlückiger With UB anything can happen, including [nasal demons](http://catb.org/jargon/html/N/nasal-demons.html) – BЈовић Mar 10 '12 at 15:36
2

This line contains multiple cases of Undefined Behavior:

*p4 = *(f(4));

The first problem is with the right hand side, as you point out f returns a pointer to an auto variable. Any use of that pointer is an error, and as you were told, in this case and in your test, the undefined behavior is not showing as a crash, but rather accessing the memory (that is somewhere in the stack).

The second problem is with the left hand side. The pointer p4 was never initialized, which means that you are also causing undefined behavior in the expression *p4, which for some reason is not making your application crash. But without knowing what the value of p4 no further analysis is possible. I.e. it could point to any location in memory, either valid or not, and any of the later operations might be changing the value at that address, so you cannot expect anything from there.

After edit:

p4 = f(4);
p8 = f(8);

This is still undefined behavior, but a simple explanation of the behavior (on which you cannot depend, even if it is common) is that the variable b is located in the same address in memory in both calls to f. This can be easily testable by printing the pointers (rather than the pointed values). The explanation of how/why this happens is that the stack frame of the first f call is reused for the second one, and because the function is exactly the same the location of all internal variables is the same for 2 consecutive calls

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    thanks david - i just changed the code a bit - apparently i copied the 2nd version accidentally. thanks for the good answer though. initially it was 2 times the same function call with 2 different values (4 and 8). i updated the question. sorry – Sebastian Flückiger Mar 09 '12 at 20:32