8

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;
}
Joedie 123
  • 337
  • 1
  • 4
  • 10
  • 2
    Nothing happened to use the space where the local variable was. Then, something did. – user253751 Jun 23 '16 at 02:45
  • what do you mean? 0.o – Joedie 123 Jun 23 '16 at 02:48
  • 5
    The behavior is undefined. You are referencing storage on the stack that is not available to you. Until something else touches it, it may still hold the value from the earlier function call, but you can't count on that. Obviously your calls to `printf` were at some point overwriting that storage. It's a bug. Just fix it and get on with life. – Tom Karzes Jun 23 '16 at 02:49
  • Assignment of `c` is UB. – chux - Reinstate Monica Jun 23 '16 at 03:53
  • That is good question. there issue seems like with the scope of variable. do not return local variable address to other function.because local variable have limited scope once function call done then it will be destroy the memory or assign to someone else. – Kanji Viroja Jun 23 '16 at 04:39
  • Well written question, but come on, a plain search for the title of this question in Google turns up at least 3 perfectly fine duplicates... – Matteo Italia Jun 23 '16 at 05:19
  • @Joedie123 The memory space where `x` used to be isn't used by `x` any more. But it might be that nothing else has been stored in that memory space yet, so it still has the last value that was stored in it, which was 123123. But then `printf` used that memory space and stored 0 in it. – user253751 Jun 23 '16 at 20:53
  • I run your code snippet in my Ubuntu 16.04 LTS 64-bit, the two printf print the same result, gcc-v5.4.0 – CodyChan Jul 12 '18 at 08:39

3 Answers3

5

The following happens:

  1. Within func1, you created the local x variable and initialised it with a value, i.e. x is on the stack now.
  2. You get the address of x and return it to main.
  3. While returning, func1 and its variables x (and, irrelevant to the question, y) are freed, 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 for x within func1, as func1 isn't active any more.
  4. Your first printf call still happens to see the old value of the memory location where x used to be (but this is not guaranteed) and
  5. the second printf call makes it apparent that something else (with the value of 0, such as the first printf's return value as described by R. Joiny) is (or was) using the same address as x within func1.

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).

FriendFX
  • 2,929
  • 1
  • 34
  • 63
5

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).

R. Joiny
  • 309
  • 7
  • 17
5

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.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • Is this really a compiler thing and not more likely an OS thing, what happens? I don't know much about compilers, but I think the OS is giving the pointer its value by assigning the needed memory on the RAM... – R. Joiny Jun 30 '16 at 07:57