C语言中含指针成员的结构体传参或赋值为浅拷贝还是深拷贝?
Great question! Let's break this down clearly so you understand exactly what's happening.
C语言中带指针成员的结构体的拷贝行为
在C语言中,带有指针成员的结构体在赋值、或者以值传递方式传递给函数时,默认执行的是浅拷贝——也就是说,只会拷贝结构体里每个成员的"表面值":对于普通成员(比如示例里的int a)是直接拷贝数值;对于指针成员(比如int *b),拷贝的是指针本身存储的内存地址,而不会去拷贝指针指向的那块内存里的实际数据。
和C类似,C语言没有自动的深拷贝机制。你提到C可以通过重载拷贝构造函数和赋值运算符实现深拷贝,但C语言没有类和构造函数的概念,完全依赖开发者手动处理指针指向的内存内容。
示例代码分析
先把你的示例代码整理格式化(注意:代码里用了new是C++语法,C语言通常用malloc,但不影响我们分析拷贝行为):
#include <iostream> using namespace std; struct data { int a; int *b; }; void test_func(struct data tes) { tes.a = 3; int *c = new int[1]; c[0] = 2; tes.b = c; std::cout << *tes.b; } int main() { struct data test; int *c = new int; *c = 4; test.a = 1; test.b = c; std::cout << *test.b; test_func(test); std::cout << *test.b; }
我们一步步拆解执行流程和输出:
- 在
main函数中,我们给test.b分配了一块内存,里面存的值是4,所以第一个std::cout会输出 4。 - 调用
test_func(test)时,因为是值传递,会创建tes结构体的副本——这就是浅拷贝:tes.a拷贝了test.a的1,tes.b拷贝了test.b的地址(也就是指向那个存4的内存块)。 - 在
test_func里,我们修改了tes.a(但这只是修改副本的成员,完全不影响main里的test),然后新分配了一块内存,让tes.b指向这块新内存(里面存2),所以这里的std::cout输出 2。 - 函数执行完毕后,
tes被销毁,但新分配的那块内存没有被释放(造成内存泄漏)。回到main,test.b仍然指向最初分配的那块存4的内存,所以最后一个std::cout输出 4。
如果是深拷贝的话,test_func的形参tes的b指针会指向一块新的内存,并且把test.b指向的4拷贝过去,但这里显然没有发生这种情况——这就是浅拷贝的典型表现。
如何在C语言中实现深拷贝
如果需要深拷贝带指针的结构体,你必须手动编写逻辑:
- 为新结构体的指针成员分配足够的内存。
- 把原指针指向的内容复制到新分配的内存里。
- 记得在不需要的时候释放这些内存,避免泄漏。
比如,你可以写一个专门的深拷贝函数:
#include <stdlib.h> struct data deep_copy_data(struct data original) { struct data copy; copy.a = original.a; // 为指针成员分配内存并拷贝内容 copy.b = malloc(sizeof(int)); if (copy.b != NULL) { *copy.b = *original.b; } return copy; }
使用这个函数来拷贝结构体,就能实现深拷贝效果了。
内容的提问来源于stack exchange,提问作者Laxmi Kadariya
相关产品推荐
相关产品推荐

