
通过一个包含指针的结构体示例,直观展示两者的区别:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义包含指针的结构体
typedef struct {
int id;
char *name; // 指针成员,指向堆内存
} Student;

// 浅拷贝:直接赋值结构体,仅拷贝指针地址
void shallow_copy_demo() {
// 初始化第一个结构体
Student s1;
s1.id = 101;
s1.name = (char *)malloc(20 * sizeof(char));
strcpy(s1.name, "Zhang San");
// 浅拷贝:直接赋值,仅拷贝指针地址
Student s2 = s1;
printf("浅拷贝后:\n");
printf("s1.name: %s, 地址: %p\n", s1.name, s1.name);
printf("s2.name: %s, 地址: %p\n", s2.name, s2.name);
// 修改s2的name,s1的name也会被修改(指向同一块内存)
strcpy(s2.name, "Li Si");
printf("修改s2.name后:\n");
printf("s1.name: %s\n", s1.name); // 输出 Li Si
printf("s2.name: %s\n", s2.name); // 输出 Li Si
// 释放内存:两次释放同一块内存,导致内存崩溃
free(s1.name);
// free(s2.name); // 执行此句会触发内存错误(double free)
}
// 深拷贝函数:为指针成员分配新内存,并拷贝内容
void deep_copy(Student *dest, const Student *src) {
// 拷贝非指针成员
dest->id = src->id;
// 为指针成员分配新内存
dest->name = (char *)malloc(strlen(src->name) + 1);
if (dest->name == NULL) { // 内存分配失败处理
perror("malloc failed");
exit(EXIT_FAILURE);
}
// 拷贝指针指向的内容
strcpy(dest->name, src->name);
}
void deep_copy_demo() {
// 初始化第一个结构体
Student s1;
s1.id = 101;
s1.name = (char *)malloc(20 * sizeof(char));
strcpy(s1.name, "Zhang San");
// 深拷贝
Student s2;
deep_copy(&s2, &s1);
printf("深拷贝后:\n");
printf("s1.name: %s, 地址: %p\n", s1.name, s1.name);
printf("s2.name: %s, 地址: %p\n", s2.name, s2.name); // 地址与s1不同
// 修改s2的name,s1的name不受影响
strcpy(s2.name, "Li Si");
printf("修改s2.name后:\n");
printf("s1.name: %s\n", s1.name); // 输出 Zhang San
printf("s2.name: %s\n", s2.name); // 输出 Li Si
// 分别释放各自的内存,无冲突
free(s1.name);
free(s2.name);
}
int main() {
printf("=== 浅拷贝示例 ===\n");
shallow_copy_demo();
printf("\n=== 深拷贝示例 ===\n");
deep_copy_demo();
return 0;
}


特性 | 浅拷贝 | 深拷贝 |
|---|---|---|
指针成员处理 | 仅拷贝指针地址(指向同一块内存) | 分配新内存,拷贝指针指向的内容 |
内存独立性 | 拷贝后结构体共享同一块堆内存 | 拷贝后结构体拥有独立的堆内存 |
修改影响 | 修改一个结构体的指针内容,另一个也变 | 修改一个不影响另一个 |
内存释放 | 易出现重复释放(double free) | 各自释放独立内存,无冲突 |
实现方式 | 直接赋值结构体即可 | 手动编写拷贝函数,分配内存+拷贝内容 |
Student s2 = s1)是浅拷贝,若结构体包含指针成员,必须手动实现深拷贝函数才能避免内存问题。