有像这样的问题,但它们与我的具体问题不够相似,让我来回答。
我的问题是如何制作一个以指针为成员的结构的深层副本,以及如何制作一个以指针为成员的结构的浅副本。然后,仅供参考,如何制作没有指针成员的结构的深层副本,以及如何制作没有指针成员的结构的浅副本(不确定最后一个是否有意义)。
假设我们有这样的结果:
typedef struct Student
{
char* first_name;
char* last_name;
int grade;
long id;
} Student;这是我用来创建一个学生的通用函数(标题很难格式化):
Student* create_student(const char* first_name, const char* last_name, int grade,long id)
{
Student *newStudentp = (malloc(sizeof(Student)));
newStudentp -> last_name = (malloc((strlen(last_name) + 1) * sizeof(char)));
newStudentp -> first_name = (malloc((strlen(first_name) + 1) * sizeof(char)));
strncpy(newStudentp -> first_name, first_name, strlen(first_name) + 1);
strncpy(newStudentp -> last_name, last_name, strlen(last_name) + 1);
newStudentp -> grade = grade;
newStudentp -> id = id;
return newStudentp;
}我试图做一个深浅不一的拷贝;
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;
}对于具有指针成员的结构的深层副本,我知道我们必须创建自己的copy函数,以便对指针做一些有意义的事情。明智的事情是...我不是sure...so,这是我对这个深度拷贝的尝试。
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);
}发布于 2011-08-02 20:19:16
您列出的进行浅层复制的代码并非如此;它实际上会破坏堆栈,并可能使程序崩溃。
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首先复制这些名称(或者包括“应该释放”标志,这样您就不必复制文字字符串)。
现在,对于没有指针(或其他引用类型)的结构,深拷贝和浅拷贝之间没有区别,因为它本身的数据结构很浅。
发布于 2011-08-02 20:10:25
浅拷贝和深拷贝之间的区别可以用一句话来解释:浅拷贝复制指针;深拷贝拷贝它们所指向的内容。
首先从你问题的最后一部分开始:如果没有指针,那么浅拷贝和深拷贝之间没有区别。
你试图做一个浅层拷贝在技术上是正确的。不过,这在逻辑上是错误的。你的delete_student()函数( frees the mallocs)不能处理浅层拷贝。它不会知道还有多少其他学生副本,并且您需要延迟free(),直到删除最后一个副本。
深度复制有一个非常相关的问题。这在技术上是不正确的。奇怪的是,您的create_student()函数显示您确实知道如何将一个char*复制到另一个first_name和last_name的深层副本中。您的copy_Student也应该做同样的事情。
发布于 2018-06-23 06:03:51
略有免责声明:我假设是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:
作为指针的s1和s2是学生结构的内存地址,它们恰好分配在堆内存中,因为create_Student()函数使用的是在堆上分配内存的malloc() (堆,这意味着即使在create_Student()退出后它也会保留)。
在s1或s2前面放一个“&”符号就像说:“给我学生结构的地址”。
&s1和&s2现在表示s1和s2指针(或内存地址)的内存位置(在堆栈中)。换句话说,你现在是两个层次的指针:一个指向一个(位于堆栈)的指针,一个指向(位于堆)的Student结构的指针。
通过指定memcpy( &s2,& s1,sizeof(学生)),您已经要求memcpy用堆栈指针s1的内容(或地址)覆盖堆栈指针s2,并损坏main()的堆栈内存的24个字节,这些内存紧跟在&s2开始的8个字节之后,紧跟在&s1之后的24个字节。因此,引用Anomie:
如果大小正确,则与s2 =s1相同;
因此,使用同样的逻辑“需要复制指针所指向的内容”,您的copy_Student()深度副本可能看起来像这样:
// 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);
}https://stackoverflow.com/questions/6911688
复制相似问题