我知道我可以逐个复制结构成员,而不是在结构上执行memcpy?这样做是否明智?在我的结构中,我有一个字符串也作为成员,我必须复制到另一个具有相同成员的结构中。我该怎么做呢?
memcpy
gzszwxb41#
通过普通赋值进行复制是最好的,因为它更短,更容易阅读,并且具有更高的抽象级别。而不是说(对代码的人类读者)“将这些位从这里复制到那里”,并要求读者考虑复制的大小参数,你只是做一个普通的赋值(“将这个值从这里复制到这里”)。对于尺寸是否正确,不能有任何犹豫。此外,如果结构中填充了大量的填充,赋值可能会使编译器发出更有效的东西,因为它不必复制填充(并且它知道它在哪里),但mempcy()不这样做,所以它总是复制您告诉它复制的确切字节数。如果你的字符串是一个实际的数组,即:
mempcy()
struct { char string[32]; size_t len; } a, b; strcpy(a.string, "hello"); a.len = strlen(a.string);
字符串然后你仍然可以使用普通赋值:
b = a;
型才能得到一份完整的拷贝。但是,对于像这样建模的可变长度数据,这不是最有效的复制方法,因为总是要复制整个数组。但是要注意,复制包含指向堆分配内存的指针的结构体可能有点危险,因为这样做会对指针产生别名,并且通常会在复制操作后使指针的所有者变得不明确。在这些情况下,“深拷贝”是唯一的选择,这需要在函数中进行。
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);
型
0sgqnhkj3#
如果结构是兼容的类型,是的,你可以这样做:
memcpy (dest_struct, source_struct, sizeof (*dest_struct));
字符串你唯一需要注意的是,这是一个 * 浅 * 副本。换句话说,如果你有一个char *指向一个特定的字符串,both 结构将指向同一个字符串。更改其中一个字符串字段的内容(char *指向的数据,而不是char *本身)也会更改另一个字符串字段。如果你想要一个简单的复制,而不必手动做每个字段,但有非浅字符串复制的额外好处,使用strdup:
char *
strdup
memcpy (dest_struct, source_struct, sizeof (*dest_struct)); dest_struct->strptr = strdup (source_struct->strptr);
型这将复制结构的整个内容,然后深度复制字符串,有效地为每个结构提供单独的字符串。而且,如果你的C实现没有strdup(它不是ISO标准的一部分),可以从这里获取一个。
g9icjywg4#
你可以memcpy结构,或者你可以像其他值一样给它们赋值。
struct {int a, b;} c, d; c.a = c.b = 10; d = c;
字符串
a7qyws3x5#
在C中,memcpy只是愚蠢地冒险。只要你让所有三个参数都完全正确,没有一个结构体成员是指针(或者,你明确地打算做一个浅拷贝),并且结构体中没有大的对齐间隙,memcpy将浪费时间循环(或者性能永远不重要),那么无论如何,memcpy。你什么也没有得到,除了代码更难阅读,对未来的变化很脆弱,必须在代码审查中手工验证(因为编译器不能),但是嘿,是的,当然为什么不呢。在C中,我们前进到了可笑的风险。你可能有不安全的memcpyable类型的成员,如std::string,这将导致你的接收结构成为一个危险的武器,无论何时使用,都会随机损坏内存。在模拟切片副本时,您可能会遇到涉及虚函数的意外情况。优化器可以为您做一些奇妙的事情,因为它在编译=时保证了完整的类型知识,但它对您的memcpy调用无能为力。在C中有一个经验法则--如果你看到memcpy或memset,就有问题。在极少数情况下,这不是真的,但它们不涉及结构。只有当你有理由盲目地复制字节时,你才可以使用memcpy。另一方面,赋值很容易阅读,在编译时检查正确性,然后在运行时智能地移动 * 值 *。没有什么坏处。
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); }
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
piah890a8#
1.可以使用结构体对文件进行读写操作。你不需要把它转换成一个'char*。结构的大小也将被保留。(这一点并不接近主题,但猜猜看:在硬存储器上的行为通常类似于RAM。)1.要移动(来回)一个字符串字段,必须使用strncpy和一个临时字符串缓冲区'\0'终止。你必须记住记录字符串字段的长度。1.要移动其他字段,可以使用点表示法,例如:NodeB->one=intvar;floatvar2=(NodeA->insidebisnode_subvar).myfl;
strncpy
'\0'
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点提到的scanf,printf,否则一个更长的操作符输入(更短),不会被截断(通过空格填充)。
NodeB->txt2fi=NodeA->txt2fi
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 *’
NodeB->txt2fi
NodeA->txt2fi
typedef
8条答案
按热度按时间gzszwxb41#
通过普通赋值进行复制是最好的,因为它更短,更容易阅读,并且具有更高的抽象级别。而不是说(对代码的人类读者)“将这些位从这里复制到那里”,并要求读者考虑复制的大小参数,你只是做一个普通的赋值(“将这个值从这里复制到这里”)。对于尺寸是否正确,不能有任何犹豫。
此外,如果结构中填充了大量的填充,赋值可能会使编译器发出更有效的东西,因为它不必复制填充(并且它知道它在哪里),但
mempcy()
不这样做,所以它总是复制您告诉它复制的确切字节数。如果你的字符串是一个实际的数组,即:
字符串
然后你仍然可以使用普通赋值:
型
才能得到一份完整的拷贝。但是,对于像这样建模的可变长度数据,这不是最有效的复制方法,因为总是要复制整个数组。
但是要注意,复制包含指向堆分配内存的指针的结构体可能有点危险,因为这样做会对指针产生别名,并且通常会在复制操作后使指针的所有者变得不明确。
在这些情况下,“深拷贝”是唯一的选择,这需要在函数中进行。
pdsfdshx2#
从C90开始,您可以简单地用途:
字符串
只要字符串存储在数组中:
型
否则,如果它是一个指针,你需要手工复制它。
型
0sgqnhkj3#
如果结构是兼容的类型,是的,你可以这样做:
字符串
你唯一需要注意的是,这是一个 * 浅 * 副本。换句话说,如果你有一个
char *
指向一个特定的字符串,both 结构将指向同一个字符串。更改其中一个字符串字段的内容(
char *
指向的数据,而不是char *
本身)也会更改另一个字符串字段。如果你想要一个简单的复制,而不必手动做每个字段,但有非浅字符串复制的额外好处,使用
strdup
:型
这将复制结构的整个内容,然后深度复制字符串,有效地为每个结构提供单独的字符串。
而且,如果你的C实现没有
strdup
(它不是ISO标准的一部分),可以从这里获取一个。g9icjywg4#
你可以
memcpy
结构,或者你可以像其他值一样给它们赋值。字符串
a7qyws3x5#
在C中,memcpy只是愚蠢地冒险。只要你让所有三个参数都完全正确,没有一个结构体成员是指针(或者,你明确地打算做一个浅拷贝),并且结构体中没有大的对齐间隙,memcpy将浪费时间循环(或者性能永远不重要),那么无论如何,memcpy。你什么也没有得到,除了代码更难阅读,对未来的变化很脆弱,必须在代码审查中手工验证(因为编译器不能),但是嘿,是的,当然为什么不呢。
在C中,我们前进到了可笑的风险。你可能有不安全的memcpyable类型的成员,如std::string,这将导致你的接收结构成为一个危险的武器,无论何时使用,都会随机损坏内存。在模拟切片副本时,您可能会遇到涉及虚函数的意外情况。优化器可以为您做一些奇妙的事情,因为它在编译=时保证了完整的类型知识,但它对您的memcpy调用无能为力。
在C中有一个经验法则--如果你看到memcpy或memset,就有问题。在极少数情况下,这不是真的,但它们不涉及结构。只有当你有理由盲目地复制字节时,你才可以使用memcpy。
另一方面,赋值很容易阅读,在编译时检查正确性,然后在运行时智能地移动 * 值 *。没有什么坏处。
chy5wohz6#
您可以使用以下解决方案来实现您的目标:
字符串
ecfdbz9o7#
只是除了其他的答案,作为一个澄清。
如果你想复制结构体,但你有结构体指针,你也可以很容易地做到这一点:
字符串
长例子:
型
输出为:
型
piah890a8#
1.可以使用结构体对文件进行读写操作。你不需要把它转换成一个'char*。结构的大小也将被保留。(这一点并不接近主题,但猜猜看:在硬存储器上的行为通常类似于RAM。)
1.要移动(来回)一个字符串字段,必须使用
strncpy
和一个临时字符串缓冲区'\0'
终止。你必须记住记录字符串字段的长度。1.要移动其他字段,可以使用点表示法,例如:
NodeB->one=intvar;
floatvar2=(NodeA->insidebisnode_subvar).myfl;
字符串
1.你可以将每个字符串嵌入到一个适合它的结构体中,以避免第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 *’
个NodeB->txt2fi
和NodeA->txt2fi
属于同一个typedef
!!我在In C, why can't I assign a string to a char array after it's declared?上找到了这个主题的一个正确而简单的答案“数组(也是字符)在C中是二等公民”!!!