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

时间:2011-02-08 08:53:30

标签: c struct copy

我知道我可以按成员复制结构成员,而不是我可以在结构上进行memcpy吗?

建议这样做吗?

在我的结构中,我有一个字符串也作为成员,我必须复制到具有相同成员的另一个结构。我该怎么做?

7 个答案:

答案 0 :(得分:61)

通过简单分配进行复制是最好的,因为它更短,更容易阅读,并且具有更高的抽象级别。而不是(向代码的人类读者)说“将这些位从这里复制到那里”,并要求读者考虑副本的大小参数,你只是做一个简单的赋值(“复制这个值来自在这里“)。关于尺寸是否正确,可以毫不犹豫。

此外,如果结构被大量填充,则赋值可能会使编译器发出更高效的内容,因为它不必复制填充(并且它知道它在哪里),但mempcy()不会所以它总是会复制你告诉它复制的确切字节数。

如果你的字符串是一个实际的数组,即:

struct {
  char string[32];
  size_t len;
} a, b;

strcpy(a.string, "hello");
a.len = strlen(a.string);

然后你仍然可以使用普通作业:

b = a;

获取完整副本。对于这样建模的可变长度数据,这不是执行复制的最有效方法,因为整个数组将始终被复制。

请注意,复制包含指向堆分配内存的指针的结构可能有点危险,因为这样做会使别名指针,并且通常会使拥有指针的模糊不清复制操作后。

对于这些情况,“深层复制”确实是唯一的选择,而且需要进入功能。

答案 1 :(得分:37)

从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);

答案 2 :(得分:15)

如果结构是兼容的类型,是的,你可以使用类似的东西:

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

答案 3 :(得分:4)

你可以memcpy结构,或者你可以像任何其他值一样分配它们。

struct {int a, b;} c, d;
c.a = c.b = 10;
d = c;

答案 4 :(得分:1)

在C语言中,memcpy仅具有极高的风险。只要您使所有三个参数完全正确,结构成员都不是指针(或者,您明确打算进行浅表复制),并且结构中没有大的对齐间隙,因此memcpy会浪费时间循环(或性能无关紧要),那么绝对是memcpy。除了难于阅读的代码,对将来的更改脆弱而且必须在代码审查中手动验证(因为编译器无法进行)的代码之外,您什么都没有得到。但是,嘿,可以肯定为什么不这样做。

在C ++中,我们前进到可笑的风险。您可能具有无法安全处理的类型的成员,例如std :: string,这将导致您的接收结构成为危险的武器,每次使用时都会随机破坏内存。在模拟分片副本时,您可能会意外涉及虚拟函数。该优化器可以为您做奇妙的事情,因为它在编译=时具有完整类型知识的保证,而对memcpy调用则无济于事。

在C ++中,有一个经验法则-如果看到memcpy或memset,则出了点问题。在少数情况下,这是不正确的,但它们不涉及结构。您只有在有理由盲目复制字节时才使用memcpy。

另一方面,

赋值易于阅读,在编译时检查正确性,然后在运行时智能地移动。没有缺点。

答案 5 :(得分:0)

  1. 您可以使用结构读取写入文件。  您不需要将其强制转换为`char *。  结构尺寸也将保留。  (这一点并不是最接近主题但猜测它:   在硬记忆上行为通常类似于RAM记忆。)

  2. 要移动(到和来自)单个字符串字段,您必须使用strncpy  和一个瞬态字符串缓冲区'\0'终止。  在某处你必须记住记录字符串字段的长度。

  3. 要移动其他字段,您可以使用点符号,例如:  NodeB->one=intvar;  floatvar2=(NodeA->insidebisnode_subvar).myfl;

    struct mynode {
        int one;
        int two;
        char txt3[3];
        struct{char 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...
    
  4. 您可以将每个字符串嵌入适合它的结构中,  避开点-2并表现得像科博尔:  NodeB->txt2fi=NodeA->txt2fi  ...但你仍然需要一个瞬态字符串  在strncpyscanf的第2点加上一printf(NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer  否则操作员输入更长(更短),  不会被截断(用空格填充)。

  5. NodeB.txt3=NodeA.txt3  将创建一个指针别名。
  6. error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’  导致编译器拒绝:  NodeB->txt2fi
  7. point-4仅适用于NodeA->txt2fi& typedef属于同一个[my_section title="Foo" the_id="123"][my_text]my example text[/my_text][/my_section] !!

    我找到的这个主题的正确而简单的答案 In C, why can't I assign a string to a char array after it's declared? "阵列(也是角色)是C"中的二等公民; !!!

答案 6 :(得分:0)

您可以使用以下解决方案来实现您的目标:

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);
}