我有一个包含字符数组的结构,没有任何其他成员函数。我正在这些结构的两个实例之间进行赋值操作。如果我没记错的话,它是在做浅拷贝。在这种情况下,浅拷贝安全吗?
I've tried this in C++ and it worked but I would just like to confirm if this behavior is safe.
我有一个包含字符数组的结构,没有任何其他成员函数。我正在这些结构的两个实例之间进行赋值操作。如果我没记错的话,它是在做浅拷贝。在这种情况下,浅拷贝安全吗?
I've tried this in C++ and it worked but I would just like to confirm if this behavior is safe.
如果通过“浅拷贝”,您的意思是在分配struct
包含数组的 a 之后,该数组将指向原始struct
的数据,那么:它不能。数组的每个元素都必须复制到新的struct
. 如果你的结构有指针,“浅拷贝”就会出现。如果没有,你就不能做浅拷贝。
当您将struct
包含数组的值分配给某个值时,它不能进行浅拷贝,因为这意味着分配给一个数组,这是非法的。因此,您获得的唯一副本是深层副本。
考虑:
#include <stdio.h>
struct data {
char message[6];
};
int main(void)
{
struct data d1 = { "Hello" };
struct data d2 = d1; /* struct assignment, (almost) equivalent to
memcpy(&d2, &d1, sizeof d2) */
/* Note that it's illegal to say d2.message = d1.message */
d2.message[0] = 'h';
printf("%s\n", d1.message);
printf("%s\n", d2.message);
return 0;
}
以上将打印:
Hello
hello
另一方面,如果你struct
有一个指针,struct
赋值只会复制指针,这是“浅拷贝”:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char *message;
};
int main(void)
{
struct data d1, d2;
char *str = malloc(6);
if (str == NULL) {
return 1;
}
strcpy(str, "Hello");
d1.message = str;
d2 = d1;
d2.message[0] = 'h';
printf("%s\n", d1.message);
printf("%s\n", d2.message);
free(str);
return 0;
}
以上将打印:
hello
hello
一般来说, given struct T d1, d2;
,d2 = d1;
等价于memcpy(&d2, &d1, sizeof d2);
,但如果结构有填充,则可能会或可能不会被复制。
编辑:在 C 中,您不能分配给数组。鉴于:
int data[10] = { 0 };
int data_copy[10];
data_copy = data;
是非法的。因此,正如我上面所说,如果您在 a 中有一个数组struct
,则分配给该结构必须在数组中按元素复制数据。在这种情况下,您不会得到浅拷贝:将术语“浅拷贝”应用于这种情况是没有任何意义的。
分配结构是按成员分配的,对于数组,这意味着分配每个项目。(这对于“多维”数组是递归完成的,它们实际上只是数组的数组。)
你是对的,它做了一个浅拷贝,即使在数组上也是如此。(我假设你没有重载 op= 相对于 C++;如果你重载它,你可以做任何你想做的事情。)
请记住,浅拷贝意味着复制某物的值,而深拷贝意味着复制某物指向或引用的值。数组的值是其中的每一项。
当您有一个执行间接的类型(例如指针)时,浅层和深层之间的区别最有意义。我发现我的回答是看待这个问题的最有用的方法,但您也可以说“浅”与“深”甚至不适用于其他类型,它们只是“复制”。
struct S {
int n;
int* p;
int a[2];
int* ap[2];
int xy[2][2];
};
void f() {
S c, d;
c = d;
// equivalent to:
c.n = d.n;
c.p = d.p;
c.a[0] = d.a[0]; // S::a is similar to your situation, only using
c.a[1] = d.a[1]; // int instead of char.
c.ap[0] = d.ap[0];
c.ap[1] = d.ap[1];
c.xy[0][0] = d.xy[0][0];
c.xy[0][1] = d.xy[0][1];
c.xy[1][0] = d.xy[1][0];
c.xy[1][1] = d.xy[1][1];
}
我在上面使用的 int 并没有改变任何语义,它对 char 数组的工作方式相同,复制每个 char。这是我代码中的 S::a 情况。
请注意,p和ap被浅拷贝(与其他所有成员一样)。如果这些指针“拥有”它们指向的内存,那么它可能不安全。(您问题中的“安全”含糊不清,实际上取决于您的期望和处理方式。)
对于一个有趣的转折,请考虑 C++ 中的 boost::shared_ptr 和其他智能指针。即使可以进行深层复制,它们也可以进行浅层复制,这仍然是安全的。