4

使用指南,我被告知数组是通过引用传递的。当结构看起来像这样时,这成立:

struct Person{
 char* name;
 int id;
}

但是当结构看起来像:

struct Person{
 char name[20];
 int id;
}

使用 seconds 结构时,name数组按值复制:

struct Person p1 = {"John", 1234};
struct Person p2 = p1;
p2.name[0] = 'L';

// p1.name[0] is still 'K'

为什么会这样?

4

3 回答 3

3

有人告诉我数组是通过引用传递的。

这并不完全正确。根本不传递数组,没有函数可以将数组作为参数。当您声明了一个函数时

void foo(int bar[]);

参数的类型foo实际上是int *,当你调用它时

int arr[23];
/* fill arr with meaningful values */
foo(arr);

指向 的第一个元素的指针按值arr传递。所有函数参数都在 C 中按值传递,无一例外。

因此,当您将 astruct Person传递给按值传递的函数时,struct会复制 the 的成员。如果其中一个成员是一个数组,那么它也会被复制,因为它是struct.

于 2013-01-28T17:07:41.517 回答
2

这对双方都成立。唯一的区别是,对于第一个结构,您只存储指向字符串的指针和 id 字段。在第二个结构中,您将整个字符串和 id 字段存储在结构中。因此第一个结构大约是。8 字节大小(假设是 32 位指针),第二个结构约为。24 字节大小。

在这两种情况下,如果您调用该函数并按值传递它,则会复制整个结构。您可以通过修改 id 字段而不是 name 字段来检查这一点。

通过引用(作为指针)将结构和数组传递给函数的原因是为了避免这种复制到堆栈上。

编辑:清除:通过访问第一个结构的 p2.name[0] ,您可以访问内存中其他位置(未复制)的(复制的)结构之外的位置。如果您访问第二个结构的 p2.name[0] ,您将访问为(复制的)结构分配的内存区域内的一个位置。

查看您的代码,我发现另一个值得注意的关键部分:当您使用字符串文字(硬编码字符串)初始化第一个结构时,写入 p2.name[0] 会导致未定义的行为(取决于工具链和操作系统,您的程序甚至可能会因此而崩溃!)

于 2013-01-28T16:50:01.003 回答
1

在第一种情况下,您的结构包含一个指向字符缓冲区的指针,在第二种情况下,结构实际上包含(读取:有空间容纳)20 个字符。

因此,在第一种情况下,当您通过值传递时,您复制的是指针,而不是值。

于 2013-01-28T16:49:19.520 回答