C 制作结构的深层副本…制作结构的浅层副本

C 制作结构的深层副本…制作结构的浅层副本,c,struct,C,Struct,有像这样的问题,但它们与我的具体问题不太相似,我无法理解 我的问题是如何制作以指针为成员的结构的深度副本,以及如何制作以指针为成员的结构的浅层副本。然后,仅供参考,如何创建没有指针成员的结构的深度副本,以及如何创建没有指针成员的结构的浅层副本(不确定最后一个副本是否有意义) 假设我们有: typedef struct Student { char* first_name; char* last_name; int grade; long id; } Stude

有像这样的问题,但它们与我的具体问题不太相似,我无法理解

我的问题是如何制作以指针为成员的结构的深度副本,以及如何制作以指针为成员的结构的浅层副本。然后,仅供参考,如何创建没有指针成员的结构的深度副本,以及如何创建没有指针成员的结构的浅层副本(不确定最后一个副本是否有意义)

假设我们有:

typedef struct Student
{
    char* first_name; 
    char* last_name; 
    int grade;
    long id;
} Student;
下面是我用来创建学生的通用函数(标题很难格式化):

我试图做一个深浅的复制品

int main()
{
    Student *s1 = create_Student("Bo","Diddly", 100, 221);
    Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
    memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
    return 0;
}
对于具有指针成员的结构的深度副本,我知道我们必须创建自己的复制函数,该函数对指针执行一些合理的操作。那个合理的东西是什么…我不确定…所以这里是我对这个深层副本的尝试

void copy_Student(Student *s1, Student *s2)
{
   s2 -> grade = s1 -> grade;
   s2 -> id = s1 -> id;
   s2 -> first_name = s1 -> *first_name;
   s2 -> last_name = s1 -> *last_name;

}
我问题的另一部分(没有指针作为成员的结构)可能只是口头解释

阅读有用评论后编辑:

浅拷贝: memcpy(s2、s1、sizeof(学生))

深度复制:

void free_student(Student* stu)
{
    free(stu -> first_name);
    free(stu -> last_name);
}

void copy_Student(Student *s1, Student *s2)
{
    s2 -> grade = s1 -> grade;
    s2 -> id = s1 -> id;
    s2 -> first_name = strdup(s1 -> first_name);
    s2 -> last_name = strdup(s1 -> last_name);
}

浅拷贝和深拷贝的区别可以用一句话来解释:浅拷贝拷贝指针;深度副本复制他们指向的内容

从问题的最后一部分开始:如果没有指针,浅拷贝和深拷贝之间没有区别

您尝试制作浅拷贝在技术上是正确的。不过,这在逻辑上是错误的。您的
delete\u student()
函数(释放mallocs的函数)无法处理浅拷贝。它不知道还有多少其他的学生副本,你需要延迟
free()
,直到删除alst副本


深度拷贝有一个非常相关的问题。这在技术上是不正确的。奇怪的是,您的
create_student
函数显示您确实知道如何将一个字符*复制到另一个字符,该字符具有
名字和姓氏的深度副本。你的
复制\u学生
也应该这样做。

与其将其视为一个副本,不如创建一个新的结构,但参数与要复制的结构相同?这是一个细微的区别,但您已经有了代码:

Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
Student *wiper = create_Student(s2->first_name, s2->last_name, 
                                               s2->grade, s2->id);
wiper
结构的克隆为
s2

要制作浅拷贝,请按照使用
s1
s2
memcpy
)所做的操作进行,或者简单地执行以下操作:

s2 = malloc(sizeof(Student));
*s2 = *s1
在这里,您已经用
s1
中相应的指针值覆盖了指针
s2
s2
中的指针,因此泄漏了内存

要执行深度复制,必须首先释放目标结构指向的所有内存。然后分配足够的内存来保存源结构指向的字符串。现在,
strncpy
字符串结束

void copy_Student(Student *s1, Student *s2)
{
   assert( ( s1 != NULL ) && ( s2 != NULL ) );

   if( s2->first_name != NULL ) free( s2->first_name );
   if( s2->last_name != NULL ) free( s2->last_name );

   s2->grade = s1->grade;
   s2->id = s1->id;

   s2->last_name = (malloc((strlen(s1->last_name) + 1)  * sizeof(char)));
   s2->first_name = (malloc((strlen(s1->first_name) + 1)  * sizeof(char)));

   strncpy(s2-> first_name, s1->first_name, strlen(s1->first_name) + 1);
   strncpy(s2-> last_name, s1->last_name, strlen(s1->last_name) + 1); 
}
与此相反:

newStudentp -> last_name = (malloc((strlen(last_name) + 1)  * sizeof(char)));
做:

您的deep copy希望执行类似的操作(与cnicutar建议的不完全相同):

cnicutar建议的问题是,它需要在strcpy之前手动分配缓冲区

如果我没记错的话:

*s2=*s1

我会做一个浅显的复制


当然,在深拷贝和浅拷贝中,必须确保释放目标指针,否则会导致内存泄漏。但是,如果您将深度复制到以前浅复制到的结构中,即使是
free
也会导致问题。

您列出的制作浅复制的代码不是;它实际上会破坏堆栈,并可能使程序崩溃

Student *s1 = create_Student("Bo","Diddly", 100, 221);
Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
如果大小正确,则与
s2=s1相同。但由于大小错误,它复制的内容太多,将覆盖s2之后内存中的任何内容。要进行真正的浅层复制,请关闭
&

memcpy(s2,s1,sizeof(Student)); //shallow copy of s1 INTO s2
深度复制的代码同样是错误的,但您的思路是正确的。深度复制背后的基本思想是,你必须复制每个字段;对于非指针类型,这与浅拷贝相同,但对于指针,您必须做一些更聪明的事情。但是,您发布的代码没有这样做。试试这个

void copy_Student(Student *s1, Student *s2)
{
    s2 -> grade = s1 -> grade;
    s2 -> id = s2 -> id;
    s2 -> first_name = strdup(s1 -> first_name);
    s2 -> last_name = strdup(s1 -> last_name);
}
请注意,为了避免内存泄漏,您还需要在分配新副本之前从
s2
中释放旧名称,创建一个
free_Student
函数来释放这些名称,并确保
create_Student
首先复制名称(或者包括“应释放”)标记,这样您就不必复制文字字符串)

现在,对于没有指针(或其他引用类型)的结构,深度副本和浅层副本之间没有区别,因为数据结构本身是浅层的。

免责声明:我假设一个64位gcc编译器与sizeof()以及8字节对齐。我也意识到这是一个几乎有7年历史的问题,但它在我的谷歌搜索中以第一的身份出现,所以我想为其他可能偶然发现它的人澄清一些事情。真的,我只是想发表评论,但这样做需要50%的声誉。这是另一个答案。。。 我不确定原始海报对指针的理解是什么,但我个人知道,我必须在内部停止将它们视为“指向”任何东西,而将它们视为某个东西的“内存地址”


您所列出的创建浅拷贝的代码有一个微妙的(但可能是灾难性的)疏忽

在main()函数中:

Student *s1 = create_Student("Bo","Diddly", 100, 221);
Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
声明本地(指针/内存地址)变量s1和s2(在堆栈上):

  • Student*s1(64位gcc上的8字节内存地址)
  • Student*s2(64位gcc上的8字节内存地址)
s1和s2是指针,是学生结构的内存地址,由于t的原因,这些结构恰好被分配到堆内存中
Student *s1 = create_Student("Bo","Diddly", 100, 221);
Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
memcpy(s2,s1,sizeof(Student)); //shallow copy of s1 INTO s2
void copy_Student(Student *s1, Student *s2)
{
    s2 -> grade = s1 -> grade;
    s2 -> id = s2 -> id;
    s2 -> first_name = strdup(s1 -> first_name);
    s2 -> last_name = strdup(s1 -> last_name);
}
Student *s1 = create_Student("Bo","Diddly", 100, 221);
Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
// I swapped the s1 and s2 arguments with
// target and source for clarity as well as their order
// to more closely mimic memcpy()
void copy_Student(Student *target, Student *source)
{
   if (target!=NULL) free_Student(target); // if target is already allocated, free it...
   assert(source != NULL);

   target->grade = source->grade;
   target->id = source->id;

   target->last_name = (malloc((strlen(source->last_name) + 1)  * sizeof(char)));
   target->first_name = (malloc((strlen(source->first_name) + 1)  * sizeof(char)));

   strncpy(target->first_name, source->first_name, strlen(source->first_name) + 1);
   strncpy(target->last_name, source->last_name, strlen(source->last_name) + 1); 
}