以下函数是否安全,是否返回指向局部变量的指针?
int * foo(void)
{
int a = 6;
int *p = &a;
return p;
}
如果没有,在什么条件下? 如果是,编译器如何保证安全性?
尝试过的测试用例:
int * foo(void)
{
int a = 6;
int *p = &a;
return p;
}
int * bar(void)
{
int b = 7;
int *p = &b;
return p;
}
int main()
{
int a = *foo();
int b = *bar();
printf("%d, %d, %d\n", 1, 2, 3); //to mess up stack
printf("%d, %d\n", a, b);
return 0;
}
它将成功打印“6,7”。但是-O2会打印“0,0”
答案 0 :(得分:3)
这样做的结果将是未定义的行为,这绝对不安全。
a
是函数的局部变量(即:automatic variable
)因此它存储在堆栈中。当函数返回堆栈帧 向上移动(或向下移动)时,剩下的内存可能会被下一个被调用的函数覆盖,因此te指针将指向内存中的方向相同,但可以是任意随机字节。
答案 1 :(得分:1)
此功能永远不安全。可能会偶然发生在某些时候做你期望的事情,但就是这样。
略微简洁:返回指向局部变量的指针始终会引发未定义的行为。未定义的行为包括此次不会发生任何不良事件的可能性,并且通常基于堆栈的C实现允许您在堆栈顶部“上方”立即取消引用指向内存的指针,大多数的时间。你的main
在函数返回后立即取消引用这些指针,这使它更有可能“工作”(特别是,你的“弄乱堆栈”printf
不会影响任何东西,因为无效的指针在那一点已经死了)。但是,安排int a = *foo()
段错误的实现将符合要求。
有趣的事实:“堆栈”这个词没有出现在C99的文本中。所有实现都需要支持递归函数调用,通常的方法是使用堆栈,但堆栈不是唯一的方法。例如,考虑Cheney on the M.T.A.,其中底层C堆栈被重新用作垃圾收集器托儿所,并且所有延续都是显式的 - C实现与Scheme实现一样允许这样做。
答案 2 :(得分:1)
简短回答,它永远不会安全,因为分配给该变量的内存迟早会被重用。
它适用于您的示例,因为它们很简单,并且在返回指针和访问它指向的内存之间堆栈上没有发生太多其他事情。
只有在返回指针的内存显式分配了malloc或类似内容时才是安全的。
此链接更好,更详细地解释了这一点: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Mips/stack.html