我有下面的代码。
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
并且代码正在运行,没有运行时异常!
输出是58
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
我有下面的代码。
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
并且代码正在运行,没有运行时异常!
输出是58
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
当前回答
你在编译程序时启用了优化器吗?foo()函数非常简单,可能已经在结果代码中被内联或替换。
但是我同意Mark B的观点,结果行为是不确定的。
其他回答
在c++中,你可以访问任何地址,但这并不意味着你应该这样做。您正在访问的地址不再有效。它之所以能工作,是因为在foo返回后没有其他东西扰乱内存,但在许多情况下它可能崩溃。试着用Valgrind分析你的程序,甚至只是优化编译它,然后看看…
因为存储空间还没有被践踏。不要指望那种行为。
正如Alex指出的那样,这种行为是未定义的——事实上,大多数编译器都会警告不要这样做,因为这很容易导致崩溃。
对于你可能遇到的令人毛骨悚然的行为,可以试试这个例子:
int *a()
{
int x = 5;
return &x;
}
void b( int *c )
{
int y = 29;
*c = 123;
cout << "y=" << y << endl;
}
int main()
{
b( a() );
return 0;
}
这将输出“y=123”,但您的结果可能会有所不同(真的!)你的指针正在敲打其他不相关的局部变量。
永远不要通过访问无效内存来抛出c++异常。您只是给出了一个关于引用任意内存位置的一般概念的示例。我也可以这样做:
unsigned int q = 123456;
*(double*)(q) = 1.2;
在这里,我简单地将123456作为double类型的地址,并对其进行写入。任何事情都可能发生:
Q实际上可能是double的有效地址,例如double p;Q = &p; q可能指向已分配内存中的某个地方,我只是在那里覆盖了8个字节。 Q指向分配的内存之外,操作系统的内存管理器向我的程序发送了一个分割错误信号,导致运行时终止它。 你中了彩票。
你设置它的方式是更合理的,返回的地址指向内存的有效区域,因为它可能只是在堆栈的下一点,但它仍然是一个无效的位置,你不能以确定的方式访问。
在正常的程序执行期间,没有人会自动检查内存地址的语义有效性。但是,像valgrind这样的内存调试器很乐意这样做,所以您应该通过它运行程序并观察错误。
如果使用::printf而不使用cout,控制台输出的内容可能会发生巨大变化。 你可以在以下代码中使用调试器(在x86, 32位,MSVisual Studio上测试):
char* foo()
{
char buf[10];
::strcpy(buf, "TEST”);
return buf;
}
int main()
{
char* s = foo(); //place breakpoint & check 's' varialbe here
::printf("%s\n", s);
}