6

I am trying to understand the stack frame in C, so I wrote a simple C code to analyze the stack frame.

  • First of all the fun1() returns an address of a local variable which is initialized to 10 to ptr which leads to a warning but that's ok... If I print the value of *ptr now it prints 10, even that's fine...

  • Next fun2() returns an address of a local variable which is not even initialized and if I try to print the value of *ptr now it prints 10 no matter if i'm returning an address of a or b...

  • To understand what is actually happening here I made use of gdb. Using gdb, I started step by step debugging and when I reached the line "return &a" in fun2(), I tried to print address of b, print &b but it printed Can't take address of "b" which isn't an lvalue.

I don't understand when I try to print the address of a, print &a it prints absolutely fine then why not address of b. * Why isn't b an lvalue when a is?

# include <stdio.h>

int * fun1() {
    int a = 10; 
    return &a; 
}

int * fun2()
{
    int a;
    int b;
    return &a;           // return &b;
}

int main ()  
{
    int *ptr;
    ptr = fun1();
    ptr = fun2();
    printf ("*ptr = %d, fun2() called...\n", *ptr);
    return 0;
}
Adarsh
  • 883
  • 7
  • 18
  • http://stackoverflow.com/a/18479996/1814023 –  Apr 25 '14 at 05:30
  • 1
    You're invoking undefined behavior. There is no guarantee that the results will make any sort of sense or do what you'd expect from the stack layout. The standard hyperbole is that the program is allowed to make [demons](http://www.catb.org/jargon/html/N/nasal-demons.html) fly out your nose. – user2357112 Apr 25 '14 at 05:32
  • 2
    You're lucky that printing `*ptr` prints 10; it is certainly not guaranteed to do so (you're invoking undefined behaviour). But you really should show all the code. In the code, the compiler probably dropped `b` as an unused variable, so it doesn't have a location, hence you can't take its address. Use `b` in the code, somehow, and you'll be able to print it. And please, don't report "something like"; be precise, and report exactly what the debugger says. – Jonathan Leffler Apr 25 '14 at 05:33
  • If you are asking for docs about the "stack frame" then this is an ABI-related request, nothing really related to any programming language in particular, you should document yourself about the ABI adopted/offered by your CPU/architecture/OS/implementation. If your problem is understanding how C works, than the focus is on a totally different topic. – user2485710 Apr 25 '14 at 05:34

2 Answers2

3

The compiler is optimizing away some code in fun2.

If you return &a, it is optimizing away int b;. If you return &b, it is optimizing away int a;. If you add some dummy computation, you will see that the addresses of returned values will be different.

int * fun2()
{
    int a;
    int b;
    int* p = &a;
    p = &b;
    return p;
}

Change main to print the returned values of fun1 and fun2.

int main ()  
{
    int *ptr;
    ptr = fun1();
    printf ("ptr = %p, fun1() called...\n", ptr);
    ptr = fun2();
    printf ("ptr = %p, fun2() called...\n", ptr);
    printf ("*ptr = %d, fun2() called...\n", *ptr);
    return 0;
}

When I run this code, I get the following sample output:

ptr = 0x7ffff98c70ec, fun1() called...
ptr = 0x7ffff98c70e4, fun2() called...
*ptr = 32749, fun2() called...
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Ya that's true if I initialize b, it returns a garbage but the same should be true if I compile with -O0 level of optimization. But when I compile it with -O0 level of optimization the result is same again i.e 10 – Adarsh Apr 25 '14 at 06:26
0

It compiles for me just fine when returning the address to b. But you aren't supposed to return the address of a local variable. Check out this link.

user2588666
  • 821
  • 1
  • 7
  • 16
  • Ya that's true but my aim here is not to accomplish anything from this code but to understand how the stack variable's address being used in one function can be re-used in another function... Thanks for the help... – Adarsh Apr 25 '14 at 07:33