Home > Software design >  C - Local variables have the same address and value
C - Local variables have the same address and value

Time:09-22

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.

CodePudding user response:

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;
}

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

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.

  • Related