c - 我对 C 中按值复制/按引用复制的理解是否正确?

标签 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)>

当一个 block 结束时,它们会被丢弃,内存会自动释放(但我们自己分配的内存不会被释放)。

如果分配给其他标识符,它们的值总是被复制。例如,下面我们有一个结构 t1分配给 t2 .这些值被复制,我们现在有两个精确的对象( t2 存储了 t1 的副本)。改变一个不会改变另一个。这不同于 javascript where t1 = t2总是会导致 t1t2指向内存中的相同位置。

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");
  }
}

下面,我们将引用(值开始的内存位置)复制到 t1t2 .标识符 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);
}

这里我们必须明确地说t1t2存储指针(*)。此外,我们必须使用箭头符号 (->) 而不是点符号 (.) 并手动分配/释放内存。

这是正确的吗?

最佳答案

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:

也许是在“好像”的意义上。真实世界的 C 实现没有您描述的文字映射。事实上,变量的标识符通常在运行时根本不可用。在程序运行之前,它们在编译和/或链接时被解析为地址。

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.

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

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.

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

Below, we have copied reference (memory location where a value starts) to t1 in t2. [...]

此时我注意到 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:

您的示例展示了一种创建指向结构对象的指针的方法,而无需声明对象本身(从而使其自动分配并与其自己的标识符相关联)。但是请注意,虽然这让人想起在 Javascript 中通过引用处理对象,但它与通过引用传递几乎没有关系,后者是关于调用函数/调用方法。

C(与 C++ 不同)没有传递引用。 C 函数调用总是按值传递,但传递的值可以是指针。据我了解,这类似于 Javascript,它也只有按值传递(传递的值可以是引用)。

关于c - 我对 C 中按值复制/按引用复制的理解是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52172819/

相关文章:

c - C 中 <linux/crc32.h> 和 <zlib.h> 的 crc32() 实现之间的区别

c - 返回指向结构体的指针

c - 无法在动态链接库中找到过程入口点axiom_attribute_create

c++ - 共享内存 (SHM) 中的 OpenSSL session 池可能吗?

c++ - 将多个对象合并到一个返回对象中

Java:用ArrayList写pojo最高效的方法

dart - 为什么Dart充当引用传递?

c# - 如何将在 C# 列表中创建的对象的地址传递给 C++ dll?

c - 理解Linux中的fork()

c++ - 使用指针合并两个排序数组的问题