将一种结构复制到另一种结构
Posted
技术标签:
【中文标题】将一种结构复制到另一种结构【英文标题】:Copying one structure to another 【发布时间】:2011-06-23 07:12:15 【问题描述】:我知道我可以逐个复制结构成员,而不是我可以在结构上执行memcpy
吗?
这样做是否可取?
在我的结构中,我还有一个字符串作为成员,我必须将其复制到另一个具有相同成员的结构中。我该怎么做?
【问题讨论】:
你为什么在标记为 C 的问题中谈论“成员函数”? 你能给我们展示一下结构或者至少是它的摘录吗?我假设该字符串不是成员 function,只是我们在这里谈论纯 C 的成员。 “字符串”是 char 数组、动态分配的 char* 还是什么? 【参考方案1】:如果结构是兼容的类型,是的,您可以使用以下内容:
memcpy (dest_struct, source_struct, sizeof (*dest_struct));
您唯一需要注意的是这是一个浅副本。换句话说,如果你有一个 char *
指向一个特定的字符串,两个结构将指向同一个字符串。
更改其中一个字符串字段的内容(char *
指向的数据,而不是 char *
本身)也会更改另一个。
如果您想要一个简单的副本,而无需手动执行每个字段,但还有非浅字符串副本的额外好处,请使用strdup
:
memcpy (dest_struct, source_struct, sizeof (*dest_struct));
dest_struct->strptr = strdup (source_struct->strptr);
这将复制结构的全部内容,然后深度复制字符串,有效地为每个结构提供一个单独的字符串。
而且,如果您的 C 实现没有 strdup
(它不是 ISO 标准的一部分),get one from here。
【讨论】:
【参考方案2】:您可以memcpy
结构,或者您可以像分配任何其他值一样分配它们。
struct int a, b; c, d;
c.a = c.b = 10;
d = c;
【讨论】:
这是否适用于问题中提到的字符串?【参考方案3】:从 C90 开始,您可以简单地使用:
dest_struct = source_struct;
只要字符串被存储在数组中:
struct xxx
char theString[100];
;
否则,如果是指针,则需要手动复制。
struct xxx
char* theString;
;
dest_struct = source_struct;
dest_struct.theString = malloc(strlen(source_struct.theString) + 1);
strcpy(dest_struct.theString, source_struct.theString);
【讨论】:
C90 之前会发生什么?如果结构包含像您的示例中那样的数组,那么 C90 之前和 C90 之后的编译器之间的结构分配有什么区别? @cesss:在 C90/C89 之前,C 没有正式的标准,所以它取决于您使用的编译器。并非所有支持分配struct
s。由于 C90 需要编译器来支持它,因此您可以确定任何符合 C90(或更高版本)的编译器都会让您这样做。【参考方案4】:
通过简单的赋值复制是最好的,因为它更短、更易于阅读并且具有更高的抽象级别。而不是说(对代码的人类读者)“将这些位从这里复制到那里”,并要求读者考虑副本的大小参数,您只是在做一个简单的分配(“从这里到这里”)。大小是否正确,可以毫不犹豫。
另外,如果结构被大量填充,赋值可能会使编译器发出更有效的东西,因为它不必复制填充(并且它知道它在哪里),但mempcy()
不会这样将始终复制您告诉它复制的确切字节数。
如果你的字符串是一个实际的数组,即:
struct
char string[32];
size_t len;
a, b;
strcpy(a.string, "hello");
a.len = strlen(a.string);
那么你仍然可以使用普通赋值:
b = a;
获取完整副本。但是对于像这样建模的可变长度数据,这并不是最有效的复制方式,因为整个数组都会被复制。
但请注意,复制包含指向堆分配内存的指针的结构可能有点危险,因为这样做会使指针别名,并且通常会使谁拥有指针变得模棱两可复制操作后。
对于这些情况,“深拷贝”确实是唯一的选择,并且需要在函数中进行。
【讨论】:
【参考方案5】:您可以使用结构来读取写入文件。 您不需要将其转换为 `char*。 结构大小也将被保留。 (这点不是最接近主题但猜测它: 在硬内存上的行为通常与 RAM 类似。)
要移动(移至和移出)单个字符串字段,您必须使用 strncpy
和一个临时字符串缓冲区'\0'
终止。
您必须在某个地方记住记录字符串字段的长度。
要移动其他字段,您可以使用点表示法,例如:
NodeB->one=intvar;
floatvar2=(NodeA->insidebisnode_subvar).myfl;
struct mynode
int one;
int two;
char txt3[3];
structchar txt2[6];txt2fi;
struct insidenode
char txt[8];
long int myl;
void * mypointer;
size_t myst;
long long myll;
insidenode_subvar;
struct insidebisnode
float myfl;
insidebisnode_subvar;
mynode_subvar;
typedef struct mynode* Node;
...(main)
Node NodeA=malloc...
Node NodeB=malloc...
您可以将每个字符串嵌入到适合它的结构中,
避开第 2 点并表现得像 Cobol:
NodeB->txt2fi=NodeA->txt2fi
...但你仍然需要一个瞬态字符串
加上一个strncpy
,如第2点所述scanf
,printf
否则操作员输入更长(更短),
不会被截断(填充空格)。
(NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer
将创建一个指针别名。
NodeB.txt3=NodeA.txt3
导致编译器拒绝:
error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
第 4 点有效,因为 NodeB->txt2fi
和 NodeA->txt2fi
属于同一个 typedef
!!
我在以下位置找到了该主题的正确且简单的答案 In C, why can't I assign a string to a char array after it's declared? “数组(也是字符)是 C 中的二等公民”!!!
【讨论】:
【参考方案6】:您可以使用以下解决方案来实现您的目标:
struct student
char name[20];
char country[20];
;
void main()
struct student S="Wolverine","America";
struct student X;
X=S;
printf("%s%s",X.name,X.country);
【讨论】:
【参考方案7】:在 C 中,memcpy 只是愚蠢地冒险。只要您完全正确地获取所有三个参数,结构成员都不是指针(或者,您明确打算进行浅拷贝)并且结构中没有大的对齐间隙,memcpy 会浪费时间循环遍历(或性能无关紧要),那么无论如何,memcpy。除了难以阅读、易受未来更改影响并且必须在代码审查中手动验证(因为编译器不能)的代码之外,您将一无所获,但是,是的,为什么不这样做。
在 C++ 中,我们前进到了可笑的风险。您可能拥有不安全的 memcpyable 类型的成员,例如 std::string,这将导致您的接收结构成为危险武器,在使用时随机破坏内存。在模拟切片副本时,您可能会遇到涉及虚函数的惊喜。优化器可以为您做奇妙的事情,因为它在编译 = 时保证了完整的类型知识,但它对您的 memcpy 调用无能为力。
在 C++ 中,有一条经验法则——如果你看到 memcpy 或 memset,那就有问题了。在极少数情况下这是不正确的,但它们不涉及结构。当且仅当您有理由盲目地 复制 bytes 时,才使用 memcpy。
另一方面,赋值很容易阅读,在编译时检查正确性,然后在运行时智能地移动值。没有缺点。
【讨论】:
“在 C++ 中,有一条经验法则——如果你看到 memcpy 或 memset,那就错了。”鉴于 std::memcpy 实际上是在 C++ 中执行某些操作的唯一合法方式,这似乎是一个强有力的声明,参见。 youtu.be/_qzMpk-22cc?t=1814以上是关于将一种结构复制到另一种结构的主要内容,如果未能解决你的问题,请参考以下文章