复制包含char数组的两个结构的标准方法是什么?
以下是一些代码:
#include stdio.h>
#include string.h>
#include stdlib.h>
typedef struct {
char* name;
char* surname;
} person;
int main(void){
person p1;
person p2;
p1.name = (char*)malloc(5);
p1.surname = (char*)malloc(5);
strcpy(p1.name, "AAAA");
strcpy(p1.surname, "BBBB");
memcpy(&p2, &p1, sizeof(person));
free(p1.name);
printf("%s\n", p2.name);
return 0;
}
行printf("%s\n", p2.name);
不打印某些内容,因为我释放了缓冲区。
我的结构的问题是它们比struct person
大。它们包含数百个char指针,我必须逐个复制每个成员。
是否有另一种方法可以复制包含char数组的两个结构而不对每个成员使用malloc
和strcpy
?
答案 0 :(得分:13)
你别无选择,只能自己提供复制功能:
void copy_person(person *dst, const person *src)
{
dst->name = malloc(strlen(src->name) + 1);
dst->surname = malloc(strlen(src->surname) + 1);
strcpy(dst->name, src->name);
strcpy(dst->surname, src->surname);
}
可能比这更详细:检查错误,将辅助函数中的strlen + strcpy
分解等等。
这就是C ++中的复制构造函数。
答案 1 :(得分:7)
是的,复制包含char 数组的结构将没有任何问题,但是使用char 指针的结构(或任何类型的指针)你将不得不手动完成。
另请注意,C语言中不需要转换malloc的返回类型(它在C ++中),并且可以隐藏malloc缺少的原型。
答案 2 :(得分:1)
如果要复制,必须为任何指针分配内存。但是,您始终可以将指针指向已分配的内存。例如,您可以执行以下操作:
p2.name = p1.name (p1.name is already allocated memory)
这是危险,因为对同一内存位置有多个引用。如果您释放p1.name
或p2.name
,则会导致危险情况。
为了复制整个内容,你必须将内存分配给struct p2的指针。
p2.name = <allocate memory>
Copy individual struct members instead of a memcpy of the entire struct
这是因为内存不是以连续的方式分配的。此外,sizeof(struct)
将为您提供结构成员的大小,而不是分配给它的内存。
例如,sizeof(p2) = 8 = sizeof(p1)= sizeof(person)
即使在为p1
的成员分配内存后也是如此。
如果成员是char数组,那将是另一种情况。
答案 3 :(得分:1)
有点开箱即用的想法:
由于结构的结构是静态的,您可以编写一个小的实用程序或脚本来为您生成复制代码。
将结构定义的源代码作为输入,然后设计一组规则来生成复制代码。
这是快照,我不知道手动编写复制代码是否更快 - 但至少这是一个更有趣的问题。
答案 4 :(得分:1)
要详细说明Alexandre C.的答案,您可能希望将malloc()
作为单个操作,以便free()
也很简单。
这种方法提供了一定程度的保护,因为单个malloc()
将成功或失败,这样您就不会遇到malloc()
在构建副本中途失败的问题。使用这种方法,您可以将person
与已被malloced的person
指针混合在一起,这样您可能希望在下面的行中有两种不同的数据类型,以便更好地标记哪个是哪个。< / p>
我提供了两种复制方法,一种使用C标准库函数strcpy()
和strlen()
,另一种使用一个简单的函数执行直接复制并返回指向它停止的位置在目标缓冲区中。
我没有尝试编译此示例,因此可能存在问题。
这种方法可能存在一个问题。由于单个字符串不是malloced,如果您使用指针移动单个字符串,并且每个字符串都是其自己的内存区域,则可能会遇到问题。这种方法假定整个对象都是需要的,或者不需要它。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char* name;
char* surname;
char* address1;
} person, *personptr;
// copy a string to destination string return pointer after end of destination string
char * StrCpyRetEnd (char *pDest, char *pSrc)
{
while (*pDest++ = *pSrc++);
return pDest;
}
personptr DeepCopyPerson (person *pSrc)
{
personptr pDest = 0;
unsigned int iTotalSize = sizeof(person);
iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char);
pDest = malloc(iTotalSize);
if (pDest) {
#if 1
// alternative one without a helper function
pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name);
pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname);
pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1);
#else
// alternative two using StrCpyRetEnd () function
pDest->name = (char *)(pDest + 1);
pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name);
pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname);
strcpy (pDest->address1, pSrc->address1);
#endif
}
return pDest;
}
int main(void){
person p1; // programmer managed person with separate mallocs
personptr p2; // created using ClonePerson()
p1.name = malloc(5);
p1.surname = malloc(5);
p1.address1 = malloc(10);
strcpy(p1.name,"AAAA");
strcpy(p1.surname,"BBBB");
strcpy(p1.address1,"address1");
p2 = DeepCopyPerson (&p1);
free(p1.name);
printf("%s\n", p2->name);
free (p2); // frees p2 and all of the memory used by p2
return 0;
}