我对C中按值复制/按引用复制的理解正确吗?

时间:2018-09-04 19:27:09

标签: c pointers pass-by-reference pass-by-value

这是我认为C代码执行的工作方式:

在包含对的给定代码块中有一个变量映射:

identifier: <address in memory where the value of a given type is located (its first byte)>

当块结束并且内存自动释放时,它们将被丢弃(但我们分配给自己的内存不会释放)。

如果将它们的值分配给其他标识符,则始终将其复制。例如,下面我们在t1中有一个分配给t2的结构。这些值已复制,现在我们有两个确切的对象(t2存储t1的副本)。改变一个不会改变另一个。这与javascript不同,在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中对待对象的方式,在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);
}

在这里,我们必须明确地说t1t2存储指针(*)。同样,我们必须使用箭头符号(->代替点符号(.)并手动分配/释放内存。

这正确吗?

1 个答案:

答案 0 :(得分:3)

  

这是我认为C代码执行的工作方式:

     

在给定的代码块中使用了一个变量映射,其中包含   对:

也许在某种意义上。实际的C实现没有您所描述的文字映射。实际上,变量标识符通常在运行时根本不可用。在程序运行之前,它们会在编译和/或链接时解析为地址。

  

当块结束并且内存自动释放时,它们将被丢弃   (但不会释放我们分配给自己的内存)。

自动分配的对象的生存期在其标识符超出范围的时候结束。这可能与您对“废弃”一词所描述的含义和含义完全不同。

  

如果将其值分配给其他标识符,则始终会复制它们。

是的,分配是复制操作。但是在这个特定问题的上下文中,重要的是要了解被复制(分配)的值是什么。特别是,指针是C语言中的一流对象,与它们所指向的对象(如果有的话)不同。将指针值分配给不同的指针与将一个指向对象的值分配给另一个指向对象的操作完全不同。

  

例如,下面我们在t1中有一个分配给t2的结构。这些值已复制,现在我们有两个确切的对象(t2存储t1的副本)。改变一个不会改变另一个。这与javascript不同,在javascript中,t1 = t2始终会导致t1,而t2则指向内存中的同一位置。

是的,在C语言中,具有结构类型的对象是可以直接访问的,分配给一个对象会修改对象本身。但是请注意,这种赋值操作很浅,即当任何结构成员是指针时,都会复制指针,从而使该成员成为原始结构的相应成员的别名。 / p>

  

下面,我们将引用(值开始的存储位置)复制到t1中的t2中。 [...]

在这一点上,我注意到C没有“引用”。它具有 pointers ,其值代表地址。这是一个非常相似的概念,但不完全相同。

但是,无论如何,您对地址操作符&和指针分配的理解似乎是正确的。

  

最后,最后一个示例显示了如何处理对象,就像在javascript中对待对象一样(非原始对象总是通过引用传递)。

您的示例演示了一种创建指向结构对象的指针的方法,而无需声明该对象本身(从而使该对象自动分配并与其自身的标识符关联)。请注意,尽管这让人想起通过Javascript中的引用来处理对象,但这与按引用传递无关,后者涉及调用函数/调用方法。

C(与C ++不同)没有传递引用。 C函数调用始终是按值传递的,但是传递的值可以是指针。据我了解,这类似于Javascript,后者也仅按值传递(传递的值可以作为引用)。