-1

I have the following C code:

void testA() {
    int x = 56;
    printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
}

void testB() {
    int y;
    printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}

int main() {
    testA();
    testB();
    return 0;
}

The print result is the following:

Address of x = 0x61fdec - Value of x = 56
Address of y = 0x61fdec - Value of y = 56

Why does testB()'s local variable y has the same address as testA()'s local variable x and inherits its value as well? They're not even in the same scope and none of them is a global variable.

  • 7
    They cannot exist at the same time, so why couldn't they share address? – tstanisl Sep 17 '21 at 22:17
  • 2
    Accessing unintialised variables results in indeterminate values. Those variables are on the stack or in registers. When the function exits the stack/register may or may be overwritten before they are used again in the next function call. If the next function uses the same stack/register then the resulting value is indeterminate. May be the same as what the previous function set or may be some other random value. – kaylum Sep 17 '21 at 22:22
  • @kaylum my question is about the similarity of the addresses and the values stored in them and not about the undefined behavior of an unitialized variable – Wassim Tahraoui Sep 17 '21 at 22:29
  • 1
    The question is speculating about undefined behavior. Speculation about undefined behavior is essentially pointless. – William Pursell Sep 17 '21 at 22:53

4 Answers4

3

It's because, at the end of the TestA function call, x goes out of scope and is cleaned up. Afterwards, y is created and assigned the same memory location.

Notice in the following code where the variables have the same scope, they have different addresses:

#include <stdio.h>

void test() {
    int x = 56;
    printf("Address of x = 0x%x - Value of x = %d\n",&x,x);
    int y;
    printf("Address of y = 0x%x - Value of y = %d\n",&y,y);
}

int main() {
    test();
    return 0;
}
Jaan
  • 330
  • 2
  • 9
  • That would make sense for the address, but if x was cleaned up that means the value of x should be deleted, therefore why is the value of x also passed to y, isn't y a new variable that just happens to be in the same address? – Wassim Tahraoui Sep 17 '21 at 22:27
  • 2
    @WassimTahraoui: Re “if x was cleaned up that means the value of x should be deleted”: What makes you think `x` was “cleaned up”? What do you think “cleaned up” means. All the C standard says about `x` is that memory is reserved for it until execution of the block it is declared in ends. So the only thing it says about the end of the lifetime of `x` is that the memory is no longer reserved. That does not mean anything changes the memory or cleans it up in any way. Seriously, where did you get the idea that anything cleans up `x`? – Eric Postpischil Sep 17 '21 at 22:31
  • 1
    @WassimTahraoui Think of memory as like a grid. When you declare x and initialize it, one of those boxes is filled with the value 56 which x is referencing. When x goes out of scope, x is cleaned up, but the value 56 stays there until it is changed. Now you declare a variable y. Y references the first available spot, which currently holds 56. – Jaan Sep 18 '21 at 00:09
2

C 2018 6.2.4 2 says:

The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it…

Objects whose identifier is declared inside a function without static or extern have automatic storage duration. The C implementation reserves memory for them automatically and releases the reservation automatically.

The lifetime begins when execution of the block the object is in begins (if it is not a variable length array) or when execution reaches the declaration (if it is a variable length array).

When the body of testA starts executing, memory is reserved for x.

Then you put 56 in x.

Then the function returns, and the block x is in stops executing. So the memory is no longer reserved for it.

Nobody comes along and cleans up that memory. Your mommy does not clean up after you, in the real world or in the computer.

Somebody might come along and use that memory. They ought to initialize it themself, but, if they do not, they might see what you put into that memory.

When testB starts executing, memory is reserved for y. Due to the way these reservations are organized, it is easy for that to be the same memory that was previously reserved for x. Then the value that appears to be in y might be the same value you put in x.

When you turn on optimization, the compiler might redesign the program and eliminate this effect. Or it might not.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

Because they can.

The C standard just requires distinct objects that exits at the same time to have distinct (read unequal) addresses. In your case none of variables x and y can be valid at the same time. So the implementation can assign them the same address.

tstanisl
  • 13,520
  • 2
  • 25
  • 40
-1

There are two totally different answers to this question.

One is that it's the C implementation's job to assign addresses to objects. It's not your job, and it's arguably not your concern. Within very broad limits, the C implementation is allowed to assign any address whatsoever to your objects, so you shouldn't be surprised at anything it assigns. A newly in-scope object happens to have the same address as a different object that just went out of scope? Well, that's "anything". Not impossible, not surprising, not your problem.

And along the same lines, the initial value of an uninitialized variable is indeterminate. You have no idea what it might be; it might be anything. It just happens to have the same value as a previous variable from a previous function? Again, that's "anything", and it's not impossible, not surprising, not your problem.

Now, I know, that's your not your question. You're imagining that it's more than a coincidence that the new variable just happens to have the exact same address, and the exact same value, as the previous variable. You're imagining that it must mean something. So that's the second answer.

Many C implementations store a function's local variables on a stack. Each variable's address is typically defined as an offset within a function call's stack frame. When one function returns, its stack frame is popped off the stack, and when the next function is called, its stack frame will occupy the same, newly-released portion of the stack. So if the previous and the next function both had the same variable(s) of the same type(s), their offsets with respect to the stack frame will probably be the same. So if the previous and the next stack frame are at the same spot on the stack, the variables within those stack frames will be at the same addresses, too.

Furthermore, when a function returns, although its stack frame is popped from the stack, that does not mean that anything actually gets cleared. And when a newly-called function has its stack frame allocated, nothing gets cleared at that point, either. So if a function has a local variable that's not explicitly initialized, its actual initial value — the value that we said was "indeterminate" — will actually be whatever bit pattern was sitting leftover on the stack, left by the last function whose stack frame was there. So if the last function had the same variable at the same stack frame offset, you may find that, lo and behold, the next function's same-offset variable will start out containing the same value that the previous function's variable had.

But this is obviously all happenstance and chance, not anything you can ever depend on. What you heard about local variables not preserving their values (let alone another function's value) is perfectly true. If you don't want an uninitialized variable like y in function testB starting out containing tantalizingly surprising values, then initialize it to a suitably unsurprising value that means something to testB.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103