将一种结构复制到另一种结构

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 没有正式的标准,所以它取决于您使用的编译器。并非所有支持分配structs。由于 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点所述scanfprintf 否则操作员输入更长(更短), 不会被截断(填充空格)。

    (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->txt2fiNodeA->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

以上是关于将一种结构复制到另一种结构的主要内容,如果未能解决你的问题,请参考以下文章

将一种类型的 unique_ptr 复制到另一种类型的工作原理

如何将一张表复制到另一张表

SQL - 将一列复制到另一列

复制表结构和内容到另一张表中的SQL语句

如何将一张图像的一部分复制到另一张图像?

将 KDoc 文档从一种方法复制到另一种方法