2010-07-22 55 views
12

复制两个包含char数组的结构的标准方式是什么?复制C中包含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数组的两个结构,而不使用每个成员的mallocstrcpy

+0

如果memcpy正在工作,如果内存未分配给p2,任何人都可以解释吗?它不应该在运行时抛出一些异常吗? – JagsVG 2015-03-29 16:30:49

+1

你的结构包含*指针*,而不是*数组*。您的指针可能包含一个char数组的地址,但是您希望该数组被复制,您必须明确地进行管理。 – 2015-05-10 10:17:49

回答

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++中的复制构造函数是for。

+4

如果你使用的是POSIX系统(例如linux),你可以使用'strdup'而不是'malloc + strcpy'。 – 2010-07-22 11:57:41

+1

@Jens:当我编写“在辅助函数中考虑因子”时,这就是我的头脑。 – 2010-07-22 12:14:43

7

是的,包含字符数组没有任何问题的工作拷贝结构,但结构与焦炭指针(或与此有关的任何类型的指针),你将不得不做手工。

另请注意,malloc的返回类型的转换在C中是不需要的(它在C++中),并且可以隐藏malloc的缺失原型。

0

如果你想做一个副本,你必须分配内存给任何指针。但是,您始终可以将指针指向已分配的内存。例如,你可以做到以下几点:

p2.name = p1.name (p1.name is already allocated memory) 

这是危险因为有一个以上的参照相同的内存位置。如果您释放p1.namep2.name,则会导致危险情况。

为了复制整个内容,您必须将内存分配给结构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数组,那将是另一种情况。

1

有点乱的创造性思维:

因为你的结构的结构是静态的,你可以写一个小工具程序或脚本来生成复制代码你。

以结构定义的源代码作为输入,然后设计一组规则来生成复制代码。

这是快速的,我不知道手动编写复制代码是否更快 - 但至少这是一个更有趣的问题。

1

若要详细说明Alexandre C.的答案,您可能需要将malloc()作为单个操作来完成,因此free()也很简单。

该方法提供了一定程度的保护,因为单个的malloc()将成功或失败,因此您不会遇到malloc()通过构建副本中途失败的问题。通过这种方法,您可以混合使用person和指向person的指针,这些指针已经被匹配,因此您可能希望有两种不同的数据类型,以便更好地标记哪个数据类型是哪个数据类型。

我已经提供了复制两种选择使用简单的函数,它直副本,并返回一个指向它的目标缓冲区离开,其中一个使用C标准库函数strcpy()strlen()和其他。

我还没有试过编译这个例子,所以可能会有问题。

这种方法有一个可能的问题。由于单个字符串没有配合,如果您正在使用指针移动单个字符串,并且每个单独的字符串都是自己的混合区域的内存,您可能会遇到问题。这种方法假定整个对象都是想要的,或者不需要它。

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