在C中将一个结构分配给另一个


146

您可以将结构的一个实例分配给另一个实例吗?

struct Test t1;
struct Test t2;
t2 = t1;

我已经看到它适用于简单结构,但它适用于复杂结构吗?
编译器如何知道如何根据数据类型复制数据项,即区分an int和string?

Answers:


151

是,如果结构是相同类型。认为它是内存副本。


72
请记住,没有深层副本,指出内存没有被复制。
GeorgSchölly10年

3
并发在这里也是一个问题。
Tim Post

16
@Tim并发不再是分配内置类型(例如整数和双精度)的问题,分配也不是原子操作。

2
好的,如果创建了副本,我以后可以使用free()释放内存吗?
Betlista

5
@Betlista您无法使用free()释放内存,因为它们是自动变量:en.wikipedia.org/wiki/Automatic_variable
joshdoe 2012年

138

是的,结构支持赋值。但是,存在一些问题:

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;

现在,两个结构的指针都指向相同的内存块-编译器不会复制指向数据的指针。现在很难知道哪个结构实例拥有数据。这就是C ++发明了用户可定义的赋值运算符的概念的原因-您可以编写特定的代码来处理这种情况。


1
我选择了它,是因为阅读它使我意识到自己回答中的错误/遗漏。
克利福德,2010年

1
+1表示实际上没有任何复制正在进行。
Tom Duckering 2010年

14
为什么将其标记为垃圾邮件?有人失去了对鼠标的控制权吗?
乔治·弗里茨彻

@gf显然也是令人反感的!

2
@rahmanisback anon对此问题的答案很明确:“编译器不会复制指向数据的数据”。struct本身的数据被清楚地复制。
Tobias

24

首先看这个例子:

下面给出了一个简单的C程序的C代码

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}

foo_assign()的等效ASM代码为

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    

正如您所看到的,分配只是在汇编中用“ mov”指令代替,分配运算符仅意味着将数据从一个存储位置移动到另一个存储位置。该分配仅对结构的直接成员执行,并且在结构中具有复杂数据类型时将无法复制。这里的COMPLEX表示您不能有指向列表的指针数组。

结构中的字符数组本身不能在大多数编译器上使用,这是因为赋值将仅尝试复制而无需查看复杂类型的数据类型。


2
您能详细说明由于哪种情况而失败,因为它似乎总是对我
有用

15

这是一个简单的副本,就像您要进行的操作一样memcpy()(实际上,某些编译器实际上会memcpy()对该代码进行调用)。C中没有“字符串”,只有指向一串字符的指针。如果您的源结构包含此类指针,则该指针将被复制,而不是字符本身。


好的,因此编译器将此转换为memcpy,请参见此处:godbolt.org/z/nPxqWc-但现在,如果我传递相同的指针ab,并且*a = *b被转换memcpy为未定义的行为,因为对于memcpy“内存区域不得重叠”。(引自手册页)。那么编译器在使用中memcpy是错误的还是我在编写这样的赋值时是错误的?
非用户

6

您是用复杂的数字表示实部和虚部的意思吗?这似乎不太可能,因此,如果不是这样,则您必须举一个例子,因为“复杂”在C语言方面没有任何具体含义。

您将获得该结构的直接内存副本。那是否是您想要的取决于结构。例如,如果结构包含一个指针,则两个副本都将指向相同的数据。这可能是您想要的,也可能不是。这取决于您的程序设计。

要执行“智能”副本(或“深度”副本),您将需要实现执行该副本的功能。如果结构本身包含指针以及也包含指针的结构,并且可能还包含指向此类结构的指针(也许就是您所说的“复杂”的意思),则很难实现,并且很难维护。一种简单的解决方案是使用C ++并为每个结构或类实现副本构造函数和赋值运算符,然后每个人都对自己的副本语义负责,可以使用赋值语法,并且维护起来更容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.