以下是我认为C代码执行的工作原理:
在给定代码块中使用的变量映射包含对:
identifier: <address in memory where the value of a given type is located (its first byte)>
当块结束并且内存自动释放时它们被丢弃(但我们自己分配的内存未被释放)。
如果分配给其他标识符,则始终复制它们的值。例如,下面我们在t1
中有一个分配给t2
的结构。这些值被复制,我们现在有两个确切的对象(t2
存储t1
的副本)。改变一个不会改变另一个。这与javascript不同,其中t1 = t2
总是导致t1
和t2
指向内存中的相同位置。
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");
}
}
下面,我们将参考(值开始的内存位置)复制到t1
中的t2
。标识符t2
映射到内存地址,其中存储在t1
中的对象的内存地址开始。 &t1 == t2
但是&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");
}
}
最后,最后一个示例显示了如何处理对象,类似于在javascript中处理它们的方式,其中非原始对象总是通过引用传递:
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);
}
在这里,我们必须明确地说t1
和t2
存储指针(*
)。此外,我们必须使用箭头符号(->
)而不是点符号(.
)并手动分配/释放内存。
它是否正确?
以下是我认为C代码执行的工作原理:
在给定代码块中使用的变量映射包含对:
或许,在“似乎”的意义上。真实世界的C实现没有您描述的文字地图。实际上,变量的标识符通常在运行时根本不可用。在程序运行之前,它们在编译和/或链接时解析为地址。
当块结束并且内存自动释放时它们被丢弃(但我们自己分配的内存未被释放)。
自动分配对象的生命周期在其标识符超出范围的位置结束。这可能与“废弃”一词所描述的含义完全相同或不同。
如果分配给其他标识符,则始终复制它们的值。
是的,赋值是一种复制操作。但是在这个特定问题的背景下,了解复制(分配)的值是很重要的。特别是,指针是C中的第一类对象,与它们指向的对象(如果有的话)不同。将指针值分配给不同的指针是将一个指向对象的值分配给另一个指向对象的完全不同的操作。
例如,下面我们在
t1
中有一个分配给t2
的结构。这些值被复制,我们现在有两个确切的对象(t2
存储t1
的副本)。改变一个不会改变另一个。这与javascript不同,其中t1 = t2
总是导致t1
和t2
指向内存中的相同位置。
是的,在C中,可以直接访问具有结构类型的对象,并且分配给一个对象可以修改对象本身。但请注意,这样的赋值操作很浅,在任何结构成员都是指针的情况下,指针被复制,使该成员成为原始结构的相应成员的别名。
下面,我们将参考(值开始的内存位置)复制到
t1
中的t2
。 [...]
我在这一点上注意到C没有“引用”。它有指针,其值代表地址。这是一个非常相似的概念,但不是一个相同的概念。
但是,在任何情况下,您对运算符地址,&
和指针赋值的理解似乎都是正确的。
最后,最后一个示例显示了如何处理对象,类似于在javascript中处理它们的方式,其中非原始对象总是通过引用传递:
您的示例显示了一种创建指向结构对象的指针的方法,而无需声明对象本身(从而使其自动分配并与其自己的标识符关联)。但请注意,虽然这让人想起通过Javascript中的引用处理对象,但它与传递引用几乎没有关系,这与调用函数/调用方法有关。
C(与C ++不同)没有传递引用。 C函数调用总是按值传递,但传递的值可以是指针。据我所知,这类似于Javascript,它也只传递值(传递的值可以是引用)。