C语言 将一个结构复制到另一个

y3bcpkx1  于 2023-08-03  发布在  其他
关注(0)|答案(8)|浏览(167)

我知道我可以逐个复制结构成员,而不是在结构上执行memcpy
这样做是否明智?
在我的结构中,我有一个字符串也作为成员,我必须复制到另一个具有相同成员的结构中。我该怎么做呢?

gzszwxb4

gzszwxb41#

通过普通赋值进行复制是最好的,因为它更短,更容易阅读,并且具有更高的抽象级别。而不是说(对代码的人类读者)“将这些位从这里复制到那里”,并要求读者考虑复制的大小参数,你只是做一个普通的赋值(“将这个值从这里复制到这里”)。对于尺寸是否正确,不能有任何犹豫。
此外,如果结构中填充了大量的填充,赋值可能会使编译器发出更有效的东西,因为它不必复制填充(并且它知道它在哪里),但mempcy()不这样做,所以它总是复制您告诉它复制的确切字节数。
如果你的字符串是一个实际的数组,即:

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

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

字符串
然后你仍然可以使用普通赋值:

b = a;


才能得到一份完整的拷贝。但是,对于像这样建模的可变长度数据,这不是最有效的复制方法,因为总是要复制整个数组。
但是要注意,复制包含指向堆分配内存的指针的结构体可能有点危险,因为这样做会对指针产生别名,并且通常会在复制操作后使指针的所有者变得不明确。
在这些情况下,“深拷贝”是唯一的选择,这需要在函数中进行。

pdsfdshx

pdsfdshx2#

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

0sgqnhkj

0sgqnhkj3#

如果结构是兼容的类型,是的,你可以这样做:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));

字符串
你唯一需要注意的是,这是一个 * 浅 * 副本。换句话说,如果你有一个char *指向一个特定的字符串,both 结构将指向同一个字符串。
更改其中一个字符串字段的内容(char *指向的数据,而不是char *本身)也会更改另一个字符串字段。
如果你想要一个简单的复制,而不必手动做每个字段,但有非浅字符串复制的额外好处,使用strdup

memcpy (dest_struct, source_struct, sizeof (*dest_struct));
dest_struct->strptr = strdup (source_struct->strptr);


这将复制结构的整个内容,然后深度复制字符串,有效地为每个结构提供单独的字符串。
而且,如果你的C实现没有strdup(它不是ISO标准的一部分),可以从这里获取一个。

g9icjywg

g9icjywg4#

你可以memcpy结构,或者你可以像其他值一样给它们赋值。

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

字符串

a7qyws3x

a7qyws3x5#

在C中,memcpy只是愚蠢地冒险。只要你让所有三个参数都完全正确,没有一个结构体成员是指针(或者,你明确地打算做一个浅拷贝),并且结构体中没有大的对齐间隙,memcpy将浪费时间循环(或者性能永远不重要),那么无论如何,memcpy。你什么也没有得到,除了代码更难阅读,对未来的变化很脆弱,必须在代码审查中手工验证(因为编译器不能),但是嘿,是的,当然为什么不呢。
在C中,我们前进到了可笑的风险。你可能有不安全的memcpyable类型的成员,如std::string,这将导致你的接收结构成为一个危险的武器,无论何时使用,都会随机损坏内存。在模拟切片副本时,您可能会遇到涉及虚函数的意外情况。优化器可以为您做一些奇妙的事情,因为它在编译=时保证了完整的类型知识,但它对您的memcpy调用无能为力。
在C
中有一个经验法则--如果你看到memcpy或memset,就有问题。在极少数情况下,这不是真的,但它们不涉及结构。只有当你有理由盲目地复制字节时,你才可以使用memcpy。
另一方面,赋值很容易阅读,在编译时检查正确性,然后在运行时智能地移动 * 值 *。没有什么坏处。

chy5wohz

chy5wohz6#

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

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

字符串

ecfdbz9o

ecfdbz9o7#

只是除了其他的答案,作为一个澄清。
如果你想复制结构体,但你有结构体指针,你也可以很容易地做到这一点:

*ptr = *ptr2;

字符串
长例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct some {
        int a;
        char b;
};

int main(void)
{
        struct some some1;
        struct some *ptr = malloc(sizeof(struct some));
        struct some *ptr2 = malloc(sizeof(struct some));
        struct some *ptr3 = malloc(sizeof(struct some));
        memset(ptr, 0, sizeof(struct some));
        memset(ptr2, 0, sizeof(struct some));

        ptr->a = 123;
        ptr->b = 'b';

        *ptr2 = *ptr;
        printf("%d %c\n", ptr2->a, ptr2->b);

        some1 = *ptr;
        printf("%d %c\n", some1.a, some1.b);

        *ptr3 = some1;
        printf("%d %c\n", ptr3->a, ptr3->b);

        return 0;
}


输出为:

123 b
123 b
123 b

piah890a

piah890a8#

1.可以使用结构体对文件进行读写操作。你不需要把它转换成一个'char*。结构的大小也将被保留。(这一点并不接近主题,但猜猜看:在硬存储器上的行为通常类似于RAM。)
1.要移动(来回)一个字符串字段,必须使用strncpy和一个临时字符串缓冲区'\0'终止。你必须记住记录字符串字段的长度。
1.要移动其他字段,可以使用点表示法,例如: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...

字符串
1.你可以将每个字符串嵌入到一个适合它的结构体中,以避免第2点,并像Cobol一样工作:NodeB->txt2fi=NodeA->txt2fi...但是你仍然需要一个临时字符串加上一个strncpy,就像在第2点提到的scanfprintf,否则一个更长的操作符输入(更短),不会被截断(通过空格填充)。

  1. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer将创建一个指针别名。
  2. NodeB.txt3=NodeA.txt3导致编译器拒绝:error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  3. point-4之所以有效,是因为NodeB->txt2fiNodeA->txt2fi属于同一个typedef!!
    我在In C, why can't I assign a string to a char array after it's declared?上找到了这个主题的一个正确而简单的答案“数组(也是字符)在C中是二等公民”!!!

相关问题