0
#include<stdio.h>

int* foo() {
  int a = 5;
  return &a;
}

void bar() {
  int a = 7;
}

void foobar() {
    int a = 97;
}

int main() {
    int* p = foo();
    bar();
    foobar();
    printf("%d", *p);

    return 0;
}

I can't understand the concept behind this behaviour. Why is the output always the value of local variable a in foobar function?

8
  • 2
    Undefined behaviour. Commented Aug 22, 2015 at 20:06
  • because in foo() you're returning a pointer to a local variable in the scope of foo() so the behavior is undefined... Commented Aug 22, 2015 at 20:10
  • You could try printing the local variables in bar() and foobar(). The chances are, the compiler has optimized the no-op functions into empty function bodies. But trying to print via the value returned by foo() is undefined behaviour; anything could happen. Commented Aug 22, 2015 at 20:11
  • For the record, this would become defined behavior IF you changed int a = 5 in foo() to int *a = malloc( sizeof ( a ) ); *a = 5 and then added the requisite free(p) after printf in main. Commented Aug 22, 2015 at 20:12
  • Just how many dups of this are there? Commented Aug 22, 2015 at 20:18

4 Answers 4

3

This is undefined behaviour since you return a pointer to a local variable, which is invalid outside its function scope. So this point in memory might be reused as it seems to be here. Do never return pointers to local variables!

Sign up to request clarification or add additional context in comments.

Comments

3

You cannot do this:

int* foo() {
  int a = 5;
  return &a;  /* variable "a" is out of scope once "foo()" returns */
}

This is "undefined behavior". The result could be different from environment to environment, compiler to compiler, or even run to run. But it's always "garbage".

Comments

2

The program has undefined bahaviour because pointer p is initialized by the address of the local variable of function foo

int* p = foo();

After exiting the function the local variable is destroyed and the pointer is invalid.

The reason for your ptogram always outputs the value of the local variable of function foobar is that it seems the functions use the same stack frame when they are called. So their local variables are placed at the same address in the stack.

If you will change function foo the following way

int* foo() {
  static int a = 5;
  return &a;
}

then the program will ouput the value of the local variable of the function that has static storage duration.

2 Comments

..an answer that offers an explanation of the observed - undefined - behavior.
@user2864740 It is not finally. My answer was among the first answers. See the time when the answer appeared. Simply it was ignored.:)
1

When a function is called the compiler provides code to prepare stack, save current stack pointer and make space for local (automatic) variables. This commonly known as function prologue. The layout of stack after prologue is more or less:

+-----------------------------+
|      Parameters if any      |
+-----------------------------+
|      Return address         |
+-----------------------------+
| copy of ESP (stack pointer) |
+-----------------------------+
| Local variables begin here  |
+-----------------------------+
|   ...                       |

Now if you have 3 functions that will develop the same layout:

      foo()                 bar()                foobar()
+----------------+    +----------------+    +----------------+
| Return address |    | Return address |    | Return address |
+----------------+    +----------------+    +----------------+
|      ESP       |    |      ESP       |    |      ESP       |
+----------------+    +----------------+    +----------------+
|     int a      |    |     int a      |    |     int a      |
+----------------+    +----------------+    +----------------+
|      ...       |    |      ...       |    |      ...       |

If you have got the address of the variable a in the first function foo() the same address will be reused when you will call bar() and foobar(). Accessing a after the call you will find the last value written there by by foobar().

If you change your functions this way:

#include<stdio.h>

int* foo() {
  int a = 5;
  return &a;
}

int* bar() {
  int a;
  int b = 7;
  return &b;
}

int* foobar() {
  int a;
  int b;
  int c = 97;
  return &c;
}

int main() {
    int* p1 = foo();
    int* p2 = bar();
    int* p3 = foobar();
    printf("%d %d %d", *p1, *p2, *p3);

    return 0;
}

Surprisingly you will read all values. The situation is now:

      foo()                 bar()                foobar()
+----------------+    +----------------+    +----------------+
| Return address |    | Return address |    | Return address |
+----------------+    +----------------+    +----------------+
|      ESP       |    |      ESP       |    |      ESP       |
+----------------+    +----------------+    +----------------+
|     int a      |    |     int a      |    |     int a      |
+----------------+    +----------------+    +----------------+
|      ...       |    |     int b      |    |     int b      |
+----------------+    +----------------+    +----------------+
|      ...       |    |      ...       |    |     int c      |
+----------------+    +----------------+    +----------------+
|      ...       |    |      ...       |    |      ...       |

BTW this go under the big family of undefined behaviors, and most important is an error. The lifespan of an automatic variable is limited to its scope, and must not be used outside.

Anyway the behavior of values on the stack is generally stable because the memory manager preserves the data of stack pages (that's why doesn't make sense to use uninitialized local variables as random values), but in future architectural designs the MM can discard unused memory and don't save it making effectively undefined the contents of these memory locations.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.