在C语言实现原型模式时,深拷贝(Deep Copy) 和浅拷贝(Shallow Copy) 的选择取决于原型对象中成员的类型(尤其是是否包含动态分配的内存)。核心原则是:确保克隆对象的独立性------修改克隆对象不会影响原对象,反之亦然。
1. 浅拷贝(Shallow Copy)的适用场景
浅拷贝仅复制对象的"表面"成员(直接赋值),不复制成员指向的动态内存。适用于:
- 所有成员都是基本数据类型 (
int
、float
、char
等)。 - 成员中没有动态分配的内存(如
malloc
分配的指针)。
示例:纯基本类型的结构体(适合浅拷贝)
c
typedef struct {
int id;
float value;
char flag;
} SimpleData;
// 浅拷贝实现(直接 memcpy)
SimpleData* shallow_copy(SimpleData* orig) {
SimpleData* copy = malloc(sizeof(SimpleData));
if (copy) {
*copy = *orig; // 直接赋值所有成员(浅拷贝)
}
return copy;
}
原因:所有成员都是基本类型,存储在结构体内部,复制后克隆对象与原对象的成员互不干扰。
2. 深拷贝(Deep Copy)的适用场景
深拷贝不仅复制对象本身,还会递归复制对象中所有动态分配的内存(如指针指向的堆内存、数组、嵌套结构体等)。适用于:
- 成员包含指针 ,且指针指向动态分配的内存(如
char*
字符串、int*
数组)。 - 成员包含嵌套结构体,且嵌套结构体中包含动态内存。
示例:含动态字符串的结构体(必须深拷贝)
c
typedef struct {
char* name; // 动态分配的字符串(需深拷贝)
int age;
} Person;
// 深拷贝实现(复制指针指向的内存)
Person* deep_copy(Person* orig) {
Person* copy = malloc(sizeof(Person));
if (!copy) return NULL;
// 1. 复制基本类型(浅拷贝部分)
copy->age = orig->age;
// 2. 深拷贝动态字符串(关键步骤)
if (orig->name) {
// 为克隆对象的name分配新内存,并复制内容
copy->name = malloc(strlen(orig->name) + 1);
if (copy->name) {
strcpy(copy->name, orig->name);
} else {
free(copy);
return NULL;
}
} else {
copy->name = NULL;
}
return copy;
}
原因 :如果对name
仅做浅拷贝(copy->name = orig->name
),则克隆对象与原对象的name
指针会指向同一块内存。修改其中一个的name
会影响另一个,违背"克隆对象独立"的原则。
3. 如何判断?------ 检查成员是否"拥有"动态内存
- 若成员是"值类型"(基本类型、枚举、不含指针的结构体):浅拷贝即可。
- 若成员是"引用类型" (指针指向堆内存、动态数组、文件句柄等):必须深拷贝,否则会导致"同一块内存被多个对象共享",可能引发:
- 重复释放(
free
同一块内存两次,导致崩溃)。 - 无意修改(一个对象修改内容,另一个对象受影响)。
- 重复释放(
4. 混合场景:部分成员深拷贝,部分浅拷贝
实际开发中,对象可能同时包含基本类型和动态内存,此时需针对性处理:
- 基本类型:浅拷贝。
- 动态内存指针:深拷贝。
示例:混合类型结构体的拷贝
c
typedef struct {
int id; // 基本类型(浅拷贝)
char* data; // 动态字符串(深拷贝)
int* scores; // 动态数组(深拷贝)
int score_count; // 数组长度(浅拷贝)
} Student;
Student* student_clone(Student* orig) {
Student* copy = malloc(sizeof(Student));
if (!copy) return NULL;
// 浅拷贝基本类型
copy->id = orig->id;
copy->score_count = orig->score_count;
// 深拷贝动态字符串
if (orig->data) {
copy->data = malloc(strlen(orig->data) + 1);
strcpy(copy->data, orig->data);
} else {
copy->data = NULL;
}
// 深拷贝动态数组
if (orig->scores && orig->score_count > 0) {
copy->scores = malloc(sizeof(int) * orig->score_count);
memcpy(copy->scores, orig->scores, sizeof(int) * orig->score_count);
} else {
copy->scores = NULL;
}
return copy;
}
总结:选择原则
场景 | 拷贝方式 | 核心操作 |
---|---|---|
成员均为基本类型(无指针) | 浅拷贝 | 直接赋值(*copy = *orig 或 memcpy ) |
成员包含动态内存指针(malloc 分配) |
深拷贝 | 为指针重新分配内存,并复制原内容 |
混合类型 | 部分浅拷贝 + 部分深拷贝 | 基本类型直接复制,动态内存指针单独深拷贝 |
本质:深拷贝的目的是让克隆对象与原对象完全独立,两者的内存空间没有重叠。在原型模式中,若克隆对象需要修改自身属性而不影响原型,必须根据成员类型正确选择拷贝方式。