在C语言中,按值将结构体传递给函数时,在临时内存区域(通常在函数栈上)创建了完整的副本。这意味着函数内部的任何修改都不会影响函数外部的原始结构体实例。
按值传递大型结构体时,会因为需要复制结构体的所有成员而面临时间和内存的开销。因此,标准实践是传递结构体的指针:
#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // 只会修改局部副本 } void modify_by_pointer(struct Data *d) { d->flag = 20; // 会修改原始结构 } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }
按指针传递的优点:
按值传递的缺点:
如果函数返回结构体的值,会发生什么?有哪些风险?
回答:
在C语言中可以按值返回结构体,例如:
struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // 返回副本 }
主要风险是性能:创建并返回结构体的副本。此外,错误地返回局部变量的地址则可能导致结构体指向无效内存:
struct Point* bad() { struct Point p = {1, 2}; return &p; // 错误:返回局部变量的地址 }
故事
在堆栈较小的嵌入式设备上,开发者按值传递了一个大结构体(1KB),导致堆栈溢出和系统间歇性崩溃。调查显示,每次复制结构体会在深层调用时导致堆栈内存不足。
故事
在企业服务器系统中,程序员返回了一个局部结构的指针,导致代码在函数退出后访问“悬挂”指针。这在生产环境中表现为罕见的严重段错误。
故事
在一个开源项目中,性能在切换到返回复杂结构体(内部包含数组)的函数后显著下降。性能分析工具显示处理器在不必要的多次复制结构体上浪费了时间。