C++调用返回指针的函数后连续两次printf输出异常是什么原因?
核心问题本质
- 你遇到的所有异常本质上是触发了C/C++的未定义行为(UB),根源有两个:一是add2函数返回了栈上局部变量的指针,二是第二个printf调用的格式符和传参数量不匹配
1. 返回局部变量指针的问题
函数内部定义的非静态局部变量是分配在栈内存上的,函数执行结束后,对应的栈帧会被操作系统回收,这块内存的内容可以被后续的其他函数调用随意覆盖。你的add2函数里的c是局部变量,函数结束后&c指向的内存已经失效,此时z2是野指针,任何对*z2的访问都是未定义行为,输出什么结果都有可能。
2. 不同写法结果差异的原因
- 连续两次调用printf的场景:第一次调用printf的时候,会在栈上开辟自己的栈帧空间,直接覆盖了之前add2函数存
c的那块内存,此时解引用z2拿到的是printf执行后留下的垃圾值,所以输出随机大数。另外你写的printf("%d\n%d\n", *z2);要求2个int类型参数,你只传了1个,参数不匹配本身也属于未定义行为,会进一步加剧输出异常。 - 同一printf输出的场景:调用printf之前还没有其他函数调用覆盖那块失效的栈内存,
*z2刚好能拿到之前的计算值,而且参数一次性压入栈中,所以看起来输出正常,但这只是未定义行为的巧合,换编译器、换编译配置、甚至换运行时机都可能出问题。 - 连续输出z1正常的场景:z1是main函数的局部变量,main函数执行结束前它对应的栈内存一直有效,而且你存储的是值本身,不是指向其他失效内存的指针,所以访问完全合法。
正确的实现方案
如果你确实需要返回指针类型的结果,可以选择以下两种安全的写法:
- 写法1:在堆上分配内存存储结果,堆内存不会随函数结束自动回收,记得用完后手动释放避免内存泄漏:
int* add2(int* a, int* b) { int* c = (int*)malloc(sizeof(int)); *c = *a + *b; return c; } // main函数使用完z2后加一行 free(z2); 释放内存
- 写法2:由外层调用方传入结果变量的地址,函数内部直接写入结果:
void add2(int* a, int* b, int* res) { *res = *a + *b; } // main中调用方式: int z2; add2(&x, &y, &z2);
如果没有必须返回指针的需求,直接用你写的第一个返回值的add函数是最安全高效的写法。
内容的提问来源于stack exchange,提问作者Quang Nguyen
相关产品推荐
相关产品推荐

