Reputation: 11610
Here's how I think a C code execution works:
There's a map of variables used in a given code block that contains pairs:
identifier: <address in memory where the value of a given type is located (its first byte)>
They are discarded when a block ends and memory is automatically freed (but memory that we allocated ourselves is not released).
Their values are always copied if assigned to other identifiers. For example, below we have a structure in t1
that is assigned to t2
. The values are copied and we now have two exact objects (t2
stores a copy of t1
). Changing one doesn't change the other. This is different from i.e. javascript where t1 = t2
would always lead to t1
and t2
point to the same location in memory.
typedef struct _thing
{
char item;
char item2;
} THING;
int main (void) {
THING t1;
t1.item = 'a';
t1.item2 = 'b';
THING t2 = t1;
t2.item = 'c';
if (t1.item == 'a') {
printf("t1.item is a");
}
}
Below, we have copied reference (memory location where a value starts) to t1
in t2
. Identifier t2
is mapped to memory address where memory address to object stored in t1
starts. &t1 == t2
but &t1 != &t2
;
int main (void) {
THING t1;
t1.item = 'a';
t1.item2 = 'b';
THING* t2 = &t1;
t2->item = 'c';
if (t1.item == 'c') {
printf("item is c");
}
}
Finally, the last example shows how to handle objects similarly to how they are treated in javascript where non-primitive objects are always passed by reference:
int main (void) {
THING* t1;
THING* t2;
t1 = (THING *) malloc (sizeof(THING));
t1->item = 'a';
t1->item2 = 'b';
t2 = t1;
t2->item = 'c';
if (t1->item == 'c') {
printf("item is c");
}
free(t1);
}
Here we have to explicitly say that t1
and t2
store pointers (*
). Also we have to use arrow notation (->
) instead of dot notation (.
) and allocate/free memory manually.
Is this correct?
Upvotes: 0
Views: 299
Reputation: 181008
Here's how I think a C code execution works:
There's a map of variables used in a given code block that contains pairs:
In an "as if" sense, perhaps. Real-world C implementations do not have literal maps such as you describe. In fact, variables' identifiers are not generally available at runtime at all. They are resolved to addresses at compile and / or link time, before the program runs.
They are discarded when a block ends and memory is automatically freed (but memory that we allocated ourselves is not released).
Automatically-allocated objects' lifetimes end at the point where their identifiers go out of scope. This may or may not have exactly the same meaning and implications as those you describe by the term "discarded".
Their values are always copied if assigned to other identifiers.
Yes, assignment is a copy operation. But in the context of this particular question, it is important to understand what the value is that is copied (assigned). In particular, pointers are first-class objects in C, distinct from the objects, if any, to which they point. Assigning a pointer value to a different pointer is an altogether different operation from assigning the value of one pointed-to object to the other pointed-to object.
For example, below we have a structure in
t1
that is assigned tot2
. The values are copied and we now have two exact objects (t2
stores a copy oft1
). Changing one doesn't change the other. This is different from i.e. javascript wheret1 = t2
would always lead tot1
andt2
point to the same location in memory.
Yes, in C, objects having structure type are directly accessible, and assigning to one modifies the object itself. But note that such an assignment operation is shallow, in the sense that when any of the structure members are pointers, the pointer is copied, leaving that member an alias of the corresponding member of the original structure.
Below, we have copied reference (memory location where a value starts) to
t1
int2
. [...]
I note at this point that C does not have "references". It has pointers, whose values represent addresses. This is a very similar concept, but not an identical one.
In any case, however, your understanding of the address-of operator, &
, and of pointer assignment appears to be correct.
Finally, the last example shows how to handle objects similarly to how they are treated in javascript where non-primitive objects are always passed by reference:
Your example shows a way to create a pointer to a structure object without declaring the object itself (and thereby having it allocated automatically and associated with its own identifier). Note well, however, that although this is reminiscent of handling objects via references in Javascript, it has little to do with pass by reference, which is about calling functions / invoking methods.
C (unlike C++) does not have pass-by-reference. C function calls are always pass-by-value, but the values passed can be pointers. As I understand it, this is analogous to Javascript, which also has only pass by value (where the values passed can be references).
Upvotes: 3