这个问题在这里已有答案:
在以下代码中,演示了两个函数 . f1()返回函数作用域中初始化局部变量的引用,f2()返回函数作用域中初始化局部变量的值 .
f2()预计会运行良好,因为本地初始化变量 . 值从堆栈传递到main .
f1()不会起作用,因为局部变量的引用在函数范围之外是无用的 . 但是,两个函数的输出似乎都没问题 .
这是测试代码;
#include <iostream>
using namespace std;
// function declarations
int& f1();
int f2();
int main()
{
cout << "f1: " << f1() << endl; // should not work!
cout << "f2: " << f2() << endl; // should work
return 0;
}
int& f1() // returns reference
{
int i = 10; // local variable
return i; // returns reference
}
int f2() // returns value
{
int i = 5; // local variable
return i; // returns value
}
输出如下;
f1: 10
f2: 5
为什么f1()工作正常,即使f1()返回局部变量的引用?
2 回答
访问范围超出范围的局部变量是未定义的行为 . 未定义的行为意味着程序可能工作,它可能是段错误,它可能打印垃圾值,一切 .
低级别的原因1是局部变量位于堆栈上 . 堆栈属于进程的可写地址空间(至少在大多数(如果不是全部)操作系统上都是如此) . 该程序可能会像它想要的那样写入它 . However ,写入堆栈是C不支持的 . C只定义局部变量,而不是调用帧或返回地址 . 它驻留在更高级别的抽象上 . 支持直接写入我所知道的堆栈的唯一语言是Assembly .
1无论如何,C标准都没有规定这个原因 .
欢迎来到 undefined behaviour !
这就是你在做什么 . 您访问已超出范围的变量 . 但是,可能是系统没有在已经存在的值上写入某些东西,这解释了行为 .
这就是为什么在实际代码中找到这样的逻辑错误很难的原因 . 因为您可能(非)幸运且变量具有正确的值(在该特定执行中) .
因此,
f1()
的返回值是对超出范围的内容的引用,而f2()
的返回值是该函数的局部变量的副本,这是正常的 .但是,下降编译器应警告您这一点,并发出以下警告:
请在编译器中使用 Enable 警告标志 . :)