C语言返回局部int变量地址与局部字符串地址的差异问题
两个C程序运行差异的底层原因
两个程序的行为差异和返回值是否为局部指针变量无关,核心是返回的指针指向的内存区域的生命周期不同。
第一个程序(返回局部int地址)异常的原因
#include <stdio.h> int *fun1() { int i = 10; return &i; // 局部变量i,因此在main中无法正常打印取值 } main() { int *x = fun1(); printf("%d", *x); }
- 这里的变量
i是存储在fun1函数栈帧中的自动(auto)变量,它的生命周期完全绑定fun1的执行周期。 - 当
fun1执行结束返回后,它的栈帧会被操作系统回收,这块内存空间会被后续的函数调用(比如后续执行的printf)覆盖重写。 - 此时返回的
&i是指向已回收栈内存的野指针,解引用这个指针属于C语言标准规定的未定义行为,大概率会出现乱码、段错误等异常。
第二个程序(返回局部char*)正常运行的原因
char *fun() { char *p = "ram"; return p; // char*是局部变量,即便如此在main中仍能正常打印,原因是什么? } int main() { char *x = fun(); printf("%s", x); return 0; }
- 这里的
p确实是fun函数栈帧上的局部指针变量,但我们返回的是p存储的值,而不是p本身的地址。 - 代码中的字符串字面量
"ram"属于C语言的字符串常量,编译时会被存放在进程地址空间的只读数据段(.rodata段),这个区域的内存生命周期和整个进程的运行周期完全一致,不会因为fun函数栈帧回收而被销毁。 - 所以
p存储的就是这个只读数据段中"ram"的首地址,返回这个地址到main函数中访问是完全合法的,自然可以正常打印。
补充对照验证
如果我们把第二个程序改成如下写法,就会和第一个int的例子一样出现未定义行为:
char *bad_fun() { // 这里arr是栈上的字符数组,会把字符串常量的内容拷贝到栈内存中 char arr[] = "ram"; // 返回栈上数组的首地址,属于野指针,访问会异常 return arr; }
这个例子完全符合第一个返回局部int地址的错误逻辑,运行会出现异常,进一步验证了核心差异是指针指向的内存区域,而不是指针本身是否为局部变量。
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

