2014-02-22 54 views
0

下面的函数是否安全,返回一个指向局部变量的指针?局部变量的安全性

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”

+1

你永远不应该返回指向局部变量 – mangusta

+0

@soon你这么快...我只是看见了,正要删除我的帖子。另外,如果-O2测试用例失败。 –

+0

成功(打印“6,7”,没有段错误等)**并不意味着它是正确的。 –

回答

3

这样做的结果将是未定义的行为并且它绝对不安全。

a是一个函数的局部变量(即:automatic variable),因此它被存储在堆栈中。当函数返回堆栈帧上移(或下移)并且留在那里的内存可能会被下一个调用函数覆盖,因此te指针将指向内存中的相同方向,但可以是任何随机字节。

1

此功能是不安全的,永远。它可能会意外地发生在你期望的某些时间,但仅此而已。

略少简洁:将指针返回到本地变量总是会引发未定义的行为。未定义的行为包括没有什么不好的事情发生的可能性这次,而且通常基于堆栈的C实现允许您在大多数时间立即在栈顶“上方”取消引用指针。您的main在函数返回后立即取消引用这些指针,这使得它更有可能“工作”(特别是,您的“弄乱了堆栈”printf不会影响任何内容,因为无效指针已经在该点已经死亡)。但是,安排int a = *foo()进行段错误的实现将符合要求。有趣的事实:单词“堆栈”不会出现在C99的文本中。所有实现都需要支持递归函数调用,通常的方法是使用堆栈,但堆栈不是唯一的方法。例如,考虑Cheney on the M.T.A.,其中底层C堆栈被重新用作垃圾收集器苗圃,并且所有延续都是明确的 - C实现将被允许作为Scheme实现来执行。

1

简而言之,它永远不会安全,因为分配给该变量的内存迟早会被重用。

它适用于您的示例,因为它们很简单,并且在返回指针和访问它指向的内存之间堆栈上没有发生太多事情。

只有当你返回指针的内存被malloc或类似地显式分配时,它才是安全的。

此链接说明了一点更好,更详细: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Mips/stack.html