在C中复制包含char指针的两个结构

问题描述 投票:12回答:5

复制包含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为每个成员?

c pointers struct
5个回答
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 ++中的复制构造函数。


7
投票

是的,复制包含char数组的struct将没有任何问题,但是带有char指针的结构(或任何类型的指针)你必须手动完成。

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


1
投票

要详细说明Alexandre C.的答案,你可能想把malloc()作为一个单独的操作,这样free()也很简单。

这种方法提供了一定程度的保护,因为单个malloc()要么成功要么失败,这样你就不会有malloc()在构建副本中途失败的问题。使用这种方法,你可以将person与指向person的指针混合,这些指针已被malloced所以你可能希望有两种不同的数据类型,以便更好地标记哪个是哪个。

我提供了两种复制方法,一种使用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;
    }

1
投票

如果要进行复制,则必须为任何指针分配内存。但是,您始终可以将指针指向已分配的内存。例如,您可以执行以下操作:

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

这是危险的,因为对同一内存位置有多个引用。如果你释放p1.namep2.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数组,那将是一个不同的情况。


1
投票

有点开箱即用的想法:

由于结构的结构是静态的,您可以编写一个小的实用程序或脚本来为您生成复制代码。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.