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

您可以将一个结构的一个实例分配给另一个实例吗,如下所示:

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

我见过它对简单结构起作用,但它对复杂结构起作用吗?
编译器如何知道如何根据数据项的类型复制数据项,即区分 int和字符串?

221425 次浏览

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

struct S {
char * p;
};


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

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

是的,如果结构是相同的类型。把它当作内存副本。

这是一个简单的副本,就像使用 memcpy()一样(实际上,一些编译器实际上为该代码生成对 memcpy()的调用)。C 中没有“ string”,只有指向一堆字符的指针。如果源结构包含这样的指针,那么将复制指针,而不是字符本身。

你说的“复数”是指包含实部分和虚部分的复数吗?这似乎不太可能,因此如果不是这样的话,您就必须给出一个示例,因为“复杂”在 C 语言中没有任何特定含义。

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

要执行“智能”复制(或“深度”复制) ,需要实现一个函数来执行复制。如果结构本身包含指针和也包含指针的结构,或许还包含指向这种结构的指针(也许这就是您所说的“复杂”的含义) ,那么这将非常难以实现,而且很难维护。简单的解决方案是使用 C + + 并为每个结构或类实现复制构造函数和赋值操作符,然后每个结构或类负责自己的复制语义,可以使用赋值语法,并且更容易维护。

首先看这个例子:

下面给出了一个简单 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 _ sign ()的等效 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 意味着不能有指向列表的指针数组。

结构中的字符数组本身在大多数编译器上无法工作,这是因为赋值只是尝试复制,甚至不会查看数据类型是否为复杂类型。

是的,您可以使用简单的赋值语句将一个结构的实例分配给另一个结构。

  • 对于包含结构成员的非指针或非指针,赋值意味着复制。

  • 对于指针结构成员,赋值意味着指针将 指向另一个指针的相同地址。

让我们看看第一手资料:

#include <stdio.h>


struct Test{
int foo;
char *bar;
};


int main(){
struct Test t1;
struct Test t2;
t1.foo = 1;
t1.bar = malloc(100 * sizeof(char));
strcpy(t1.bar, "t1 bar value");
t2.foo = 2;
t2.bar = malloc(100 * sizeof(char));
strcpy(t2.bar, "t2 bar value");
printf("t2 foo and bar before copy: %d %s\n", t2.foo, t2.bar);
t2 = t1;// <---- ASSIGNMENT
printf("t2 foo and bar after copy: %d %s\n", t2.foo, t2.bar);
//The following 3 lines of code demonstrate that foo is deep copied and bar is shallow copied
strcpy(t1.bar, "t1 bar value changed");
t1.foo = 3;
printf("t2 foo and bar after t1 is altered: %d %s\n", t2.foo, t2.bar);
return 0;
}