When changing the value of a variable in C, is a n

2019-01-20 11:39发布

问题:

I know that 'mutable' and 'immutable' are terms that should be used to describe the ability for objects to change value in object oriented languages such as Java and Objective C. However, I would like to bring it up because it relates to my question regarding primitives data. I know that when I change the value of a variable holding immutable object, I am in fact creating a new object. I wonder, however, if primitives data in C behave similarly to immutable objects. By that I mean, when I change the value of a variable holding primitive data, a new data is created and referenced by the variable. Or do the existing primitives actually mutated/modified the stored data values?

Edit #1:

Issue #1: I would like to clear up some misunderstandings (either on my part or on others) because I did not make it clear when I said "when I change the value of a variable holding immutable object, I am in fact creating a new object." When I said that, I did not mean to assign the variable to an existing object. For example:

// Example 1: I did not mean this
-------------------------
String x = "Hello World";
String y = x;
-------------------------

// Example 2: What I meant is this
-------------------------
String x = "Hello World";
//This will print out "Hello World"
System.out.println(x);

x = "Goodbye World";
//This will print out "Goodbye World"
System.out.println(x);
-------------------------

Of course, assigning variable y to variable x as in Example 1, which was the case you guys brought up, only reference variable y to the object that x is referencing. Of course, in this scenario, there is no new object; just the same object “Hello World” being referenced by 2 variables.

What I meant is when x = “Goodbye World” in Example 2, the variable x is referencing a new String object with the values “Goodbye World”, instead, of the first String object “Hello World” that x was initialized with. String is an Immutable object in Java. The only way to change the values for a String variable is to let the variable reference an existing object OR a new String object. If there is no existing object (“Goodbye World” String object has not been created anywhere), then the above code just created a new String object and reference x to it. Am I right? If not, please correct me.

Issue #2: I would like to sum up the answers, especially one from Ulfalizer:

1) There are actually 2 forms in which variable can exist:

a) “Memory Address” - this is the case for variables in C language, as well as Java and Objective C in regard to primitive-type data. For instance: int x = 1. The variable x here is an actual memory address itself, which has type integer and is initialized with the value 1.

b) “Reference” - this is the case for most variables in Java, in regard to non-primitive-type data (objects). For instance: String x = “Hello World”. The variable x is just a pointer/reference to ‘a memory address existing somewhere’, which holds the value “Hello World” as its content.

2) Variables for primitive-type data in C, Java, and Objective C behave as “Memory Address”. Hence, when I do this:

-------------------------
int x = 10;
x = 2;
-------------------------

The value of x variable (aka - memory address) is actually changed from 10 to 2. In other words, value stored in “Memory Address” variables can be modified/changed.

3) In C language, a variable can also behave as a reference if it is declared with ‘*’ - pointer type. I will use Ulfalizer’s example: int *ptr. ptr is a pointer variable that can point to another variable (aka memory address) such as: ptr = &x. If x is initialized as: int x = 10, then x is an actual memory address that holds the value 10. So in the codes below

-------------------------
int x;
int *ptr;
ptr = &x;
*ptr = 1;
-------------------------

I can actually modified the value stored in x variable (aka - memory address) through the ptr pointer-variable.

Please confirm if my interpretations are correct/false. Thank you.

回答1:

The best way to understand how C works is to think of it as high-level assembly language. Variables are simply locations in memory, and assigning a value to a variable stores the value into that location. From a high-level language perspective, that would be mutation in its purest form.

In C, a declaration/definition like

int x;

tells the compiler to reserve some memory for the int variable x. (Inside a function, the memory would come from the stack. At global scope, it would come from the data segment.)

An assignment like

x = 7;

simply generates code to copy the value 7 into that memory location. Similarly, an assignment like

x = y;

generates code to copy the int value stored at y's memory location into x's memory location. (Assume y is another int.)

The same logic also holds for more complex types than ints.

In Java, variables are references instead (for non-primitive types anyway), and can refer to different objects at different times. To get something similar to references in C, you have to explicitly define a pointer variable -- a variable that holds an address -- and point it to (assign it the address of) different objects at different times.

(I included the below example just in case you're interested.)

The & operator is used to get the address of a variable in C, so that &x would be the address of x for example. The * operator gives the pointed-to object when applied to a pointer. Here's an example of how a pointer could be used to refer to different variables at different times:

int x;
int y;
/* Declares 'ptr' as a pointer, and says that it points to an int.
   The pointed-to type is used by the compiler for type checking
   and type conversions. */
int *ptr;

ptr = &x; // Store the address of 'x' in 'ptr'.
*ptr = 1; // Store 1 into the memory 'ptr' points to ('x').
ptr = &y; // Store the address of 'y' in 'ptr'.
*ptr = 2; // Store 2 into the memory 'ptr' points to ('y').

The end result of the above code would be to set x to 1 and y to 2. This is a silly example of course, but hopefully it should get the idea across.

(C99 and later support //-style comments by the way.)

Answers for issues

(Caveat: My Java is a bit rusty, so I had to do some reading up. Hopefully the details should be correct. Feel free to correct me.)

Issue #1

The assignment

x = "Goodbye World";

would have the effect of making x refer to a String object with the value "Goodbye world". Exactly when this String object is created shouldn't make a difference, as long as it's created before it's assigned to x (or any other variable).

It might be created just before the assignment is executed, or when the program starts. Normally you wouldn't be able to tell the difference.

Issue #2

It sounds like you have the high-level concepts down, and your C code is correct.

(It's more correct to say that "ptr is a pointer" than to say that "*ptr is a pointer" though. There's some syntactic obscurity in C that makes it more natural to put the * next the name in the declaration (IMO), but you can also write the declaration like int* ptr; for that case. Things only start to get weird when you declare many variables in the same line.)

When talking about how Java is implemented, references might have to be a bit more advanced than just pointers to objects under the hood. For example, the JVM might move objects around in memory (which would change their address) to reduce memory fragmentation, but references must still remain valid. One way to do it would be to "fix" pointers whenever objects are moved, another to have references be indices into a table of pointers instead. Regardless of how it's done in the JVM implementation, pointer is the right thinking at least.

Since each reference in Java has a pointer field (at a high level, ignoring exactly how the implementation does it), and since this field isn't needed for primitive types, one possibility is to reuse the pointer field and store the value in it instead for primitive types.

For example, an assignment like

x = 1;

might store the value 1 directly into the pointer field of the reference x. Techniques like this are pretty common.

As a side note, a union can be used to in C to store two different types (e.g., an int and a pointer) in the same place in memory so that they overlap. Of course, assigning to one of the types would change the value for the other type too.



回答2:

It should be the current primitive modified. I tested using a simple code here, and it refers to the same address.

#include <stdio.h>

int main(void) {
    // your code goes here
    int a = 5;

    printf ("%p = %i\n", (void*) &a, a);
    a = 10;
    printf ("%p = %i\n", (void*) &a, a);

    return 0;
}