当按值提供给函数时,结构的数组字段是不是会被完全克隆?

Posted

技术标签:

【中文标题】当按值提供给函数时,结构的数组字段是不是会被完全克隆?【英文标题】:Does the array field of a struct get entirely cloned when fed by value to a function?当按值提供给函数时,结构的数组字段是否会被完全克隆? 【发布时间】:2019-02-18 03:54:09 【问题描述】:

在 C 中:

struct 按值(通过参数)发送到函数时,会创建一个新的 struct,因此更改函数内部的结构不会改变原来的结构。

当一个数组按值发送(通过参数)到函数时,会创建一个新的指针,因此在函数内部更改数组不会改变原始数组,但是改变函数内部的数组值(因为我们有指向原始数组的指针)会改变原始数组中的值。

当带有 array 字段的 struct 按值发送(通过参数)到函数时,????? 被创建,因此更改函数内部的数组(指针)不会更改原始数组,更改数组值不会更改原始数组中的值。

第三点是否意味着 structarray 字段在发送到函数时将被完全克隆?为什么不只是使用指针呢?规范是怎么说的?

我玩过的一段代码:

typedef struct 
    int value;
    int array[3]; /* initialized to 0 by default */
 Struct_t;

void foo(Struct_t structure)

    printf("-- %p\n", structure.array); /* Pointer to local array */

    structure.value = 1;
    *structure.array = 1;       /* Won't change the original array */
    *(structure.array + 1) = 1; /* Won't change the original array */
    structure.array[2] = 1;     /* Won't change the original array */


int main()

    Struct_t s =  .value = 0 ;

    foo(s);

    printf("-- %p\n", s.array); /* Pointer to original array */

    printf("%d\n", s.value);
    printf("%d\n", s.array[0]);
    printf("%d\n", s.array[1]);
    printf("%d\n", s.array[2]);

输出:

-- 0x7ffe8f17d194
-- 0x7ffe8f17d1b4
0
0
0
0

【问题讨论】:

数组是结构的一部分,因此它也将被复制(其中的所有值)。如果它是一个指针,则只会复制指针,因此将指向与原始指针相同的内存。 "改变函数内部的数组不会改变原来的数组,而是改变函数内部的数组值" an "array" 是它的“”/“元素”,仅此而已。 【参考方案1】:

OP 的“发送数组时...”需要澄清。

当一个数组(通过参数)按值发送到函数时,会创建一个新指针,因此更改函数内部的数组不会更改原始数组,但会更改函数内部的数组值(因为我们有指向原始数组的指针)将改变原始数组中的值。 (OP)

当一个数组(如下面的s[])传递给strcpy(char *s1, const char *s2) 时,首先发生转换。对象s 被转换为数组第一个元素的地址。 strcpy() 不接收s[] 作为s1 参数,而是接收&s[0] 值的副本。

char s[6] = "Hello";
strcpy(s, "World");

strcpy() 内,s1 不是数组s1 是指向 char 的指针。 strcpy() 没有“更改函数内的数组”的概念,因为函数不知道 s1 指向数组内存、分配的内存或其他任何东西。 strcpy() 理解 s1 指向 char


第三点是否意味着结构的数组字段在发送到函数时将被完全克隆?

是的。当一个对象被传递给 C 中的函数时,它可能会被转换,然后按值传递。这很像任何任务。转换后对象的内容被复制到目的地。如果对象是struct, union, int, double, void*, int(*)() 等或包含数组的struct,则在转换后没有区别。

int a;
double b;
a = 5;  // 5 is copied to a
b = a;  // a is converted to double and copied to b


char s[6] = "Hello";
char *e;
void *v;
e = s; // s is converted to the address on the first array element and then copied to e
v = e; // e is converted to a `void*` and then copied to v

Struct_t f = 0;
Struct_t g;
g = f; // f is copied to g

【讨论】:

【参考方案2】:

第三点是否意味着结构的数组字段在发送到函数时将被完全克隆?

是的。

为什么不只使用指针来代替?

因为没有指针。数组不是指针。 (More on this here.)

【讨论】:

【参考方案3】:

C 中,一切都是按值传递的。

    当我们通过值传递时,我们将变量的副本传递给函数。

    当我们通过引用传递时,我们将变量的别名传递给函数。

    它将指针的值,地址,复制到函数中。

如果 struct 按值传递给函数,则该函数的 bytes struct 被复制为函数参数。对此所做的任何事情 struct 函数内更改副本,而不是原始 struct

【讨论】:

这是否意味着结构中的数组将完全是该结构的一部分,而不仅仅是指向内存中其他位置的值的指针?似乎是这样,因为 sizeof(struct) 是结构中数组中所有元素大小的总和。但是这样做有特定的原因吗?这不会导致性能问题吗? 我知道在 K&R 中不允许按值传递 structs 并且是后来添加的。新规范对此有何评论? struct 中的数组实际上是什么,为什么会这样? @DorinBotan 该数组是结构的一部分。使用sizeof(Struct_t) 进行验证(注意:可能比预期的要大 - 请参阅Why isn't sizeof for a struct equal to the sum of sizeof of each member?)【参考方案4】:

结构是内存的预定义结构,具有一定的内存布局。通过将数组添加到结构中,数组的实际内存位于结构中而不是指针中。这就是为什么它必须与结构的其余部分一起复制。

数组不是指针,数组有一个特定的不可更改的内存位置,而指针可以指向任何你想要的地方。

【讨论】:

以上是关于当按值提供给函数时,结构的数组字段是不是会被完全克隆?的主要内容,如果未能解决你的问题,请参考以下文章

JS是按值传递还是按引用传递

Java函数参数是不是总是按值传递数组? [复制]

为啥不允许将数组按值传递给 C 和 C++ 中的函数?

按值传递和返回结构(带有数组成员)

试图取消引用一个接口,该接口是一个指向后端结构对象的指针,以便我可以按值传递给函数

为啥要在 C 中声明一个只包含数组的结构?