How are variable values stored in C?

Viewed 557

Let's say I have the following C code:

int x= 4;
int y = x;
printf("x:%d,y:%d\n",x,y);

X now references the memory location where the '4' is stored and prints as 4. y references x so it will also print 4. So why is it that when I change the value of x, eg x=6;, y doesn't get changed also? I must be misunderstanding something. Is it the same for all languages?

I couldn't find an answer to my question anywhere (probably because of poor wording).

6 Answers

Your understanding is completely wrong.

When you write int x = 4;, the x represents an actual memory location on the stack, that then gets filled with the value 4. x is irrevocably linked with that piece of memory - when x goes out of scope the memory also disappears.

When you write int y = x; again y represents an actual piece of memory. It does not 'refer' to x, instead, the contents of x are copied into y.

Is it the same for all languages?

No, different languages can and do have completely different semantics. However the way C does it is usually called value semantics.

y never references x. The assignment operator, =, copies values. x is just a value of 4, of int type. int y = x is assigning the current value of x to y, copying it in the process.

To behave like you're describing, y would need to be a pointer to an int, int *, and it would be assigned the address of x, like so:

#include <stdio.h>

int main(int argc, char *argv[]) {
    int x = 4;
    int *y = &x;
    
    
    printf("before: x: %d, y: %d\n", x, *y);
    
    x = 123; // modify x
    
    printf("after:  x: %d, y: %d\n", x, *y);
}

X now references the memory location where the '4' is stored

No, 4 isn't stored anywhere, it's a parameter to a mov. x has its own memory location that holds an integer value, in this case 4.

y references x

No, y also has its own memory location that stores an integer, also in this case 4.

So why is it that when I change the value of x, eg x=6;, y doesn't get changed

They're both different memory locations, changing one has no impact on the other.

y references x so it will also print 4.

This is your basic misunderstanding. The y variable is not a reference; it is a variable of type int that has no implicit connection to x whatsoever. When the int y = x; initialization is performed, the current value in the x variable is copied to the y variable.

Any subsequent changes to the values of either x or y will not affect the value of the other (unless an explicit reassignment from one to the other is performed).

Is it the same for all languages?

Well, I'm not even going to attempt to answer for "all languages!" However, a language that is, in some ways, 'close' to C is C++. For the code you have shown, the behaviour (and the explanation above) will be the same for C and C++. However, in C++, you can define a variable as a reference!

Simply adding the & character in its declaration will make y a reference variable; in so doing, changing x will also change the displayed value of y. Try compiling the following code (be sure to use a C++ compiler) and testing it as is and using the commented-out line, instead:

#include <iostream>

int main()
{
    int x = 4;
//  int y = x;   // Using this line, the value of "y" won't change...
    int& y = x;  // ... but adding the "&" makes "y" a REFERENCE.
    printf("x:%d,y:%d\n", x, y); // x:4,y:4
    x = 6;
    printf("x:%d,y:%d\n", x, y); // x:6,y:6 (with the "&") or x:6,y:4 (without the "&")
    return 0;
}

For these two variables

int x= 4;
int y = x;

the compiler allocates their own memory extents with sizes that correspond to the size of an object of the type int, The value of the variable x that is the value stored in the memory extent allocated for the variable x is used to initialize the variable y that is its memory extent.

So if you when write for example

x = 6;

then the integer constant 6 is stored in the memory extent allocated for the variable x. The variable y will stay unchanged.

If to speak about references then in C pointers provide references to entities (functions or objects).

If you will write for example

int *px = &x;

then the pointer px provide a reference to the variable x.

So pointers are used in the mechanism of passing objects to functions by reference. Consider the following demonstrative program.

#include <stdio.h>

void f( int *px )
{
    *px = 10;
}

int main(void) 
{
    int x = 1;
    
    printf( "Before calling f() x = %d\n", x );
    
    f( &x );
    
    printf( "After  calling f() x = %d\n", x );

    return 0;
}

The program output is

Before calling f() x = 1
After  calling f() x = 10

In the program the variable x declared in main is passed to the function f by reference through a pointer to it.

It's not the same for all languages. Is it the same for C-style languages, like C++ and such? Normally, yes.

Importantly, x doesn't reference a "memory location". It just represents an object (in C parlance, meaning "thing that you can change and pass around") that has a particular value. When compiled that x might be stored in memory, in a register, or optimized out and eliminated entirely.

For example:

int x = 1;
int y = x + 1;
int z = 4;

printf("x:%d,y:%d\n",x,y);

Here y will be 2, that can be determined at compile time, x will be 1, and z doesn't matter so it might even get deleted. y isn't computed based on x, it's computed based on static analysis of the code where the compiler rightfully asserts that it can only ever be 2, so the x factor is optimized out.

When you change y you're changing a separate thing, it has no effect on x unless you explicitly make that assignment.

This is not true in a language like C++ where references exist, as those are like variable aliases:

int& y = x; // Same as `x`, where `y` is just another name for same

Note that this is limited as well, like if int y = x + 2 you can't use references, as you're not referencing a variable. That's an expression.

In some languages an assignment like this is treated more in the mathematical sense, as in y is always x + 2 depending on whatever value x has at that moment. Functional programming languages tend to employ this model, but the specifics differ considerably.

What you're probably asserting is "Do variables work like this in imperative programming languages?" where the answer is normally yes.

Related