我有下面的代码。
#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
怎么可能呢?局部变量的内存在其函数之外不是不可访问的吗?
当前回答
永远不要通过访问无效内存来抛出c++异常。您只是给出了一个关于引用任意内存位置的一般概念的示例。我也可以这样做:
unsigned int q = 123456;
*(double*)(q) = 1.2;
在这里,我简单地将123456作为double类型的地址,并对其进行写入。任何事情都可能发生:
Q实际上可能是double的有效地址,例如double p;Q = &p; q可能指向已分配内存中的某个地方,我只是在那里覆盖了8个字节。 Q指向分配的内存之外,操作系统的内存管理器向我的程序发送了一个分割错误信号,导致运行时终止它。 你中了彩票。
你设置它的方式是更合理的,返回的地址指向内存的有效区域,因为它可能只是在堆栈的下一点,但它仍然是一个无效的位置,你不能以确定的方式访问。
在正常的程序执行期间,没有人会自动检查内存地址的语义有效性。但是,像valgrind这样的内存调试器很乐意这样做,所以您应该通过它运行程序并观察错误。
其他回答
它之所以能工作,是因为自从a被放入堆栈以来,堆栈(还没有)被改变过。 在再次访问a之前调用一些其他函数(它们也调用其他函数),你可能不会再那么幸运了……: -)
你的代码风险很大。你正在创建一个局部变量(在函数结束后被认为是被销毁的),并且在该变量被销毁后返回该变量的内存地址。
这意味着内存地址可能是有效的,也可能是无效的,您的代码将容易受到可能的内存地址问题的影响(例如分割错误)。
这意味着你正在做一件非常糟糕的事情,因为你正在把一个内存地址传递给一个根本不可信的指针。
考虑这个例子,并测试它:
int * foo()
{
int *x = new int;
*x = 5;
return x;
}
int main()
{
int* p = foo();
std::cout << *p << "\n"; //better to put a new-line in the output, IMO
*p = 8;
std::cout << *p;
delete p;
return 0;
}
不像你的例子,在这个例子中你是:
将int的内存分配到本地函数中 当函数过期时,该内存地址仍然有效(它不会被任何人删除)。 内存地址是可信任的(该内存块不被认为是空闲的,因此在删除它之前不会被覆盖) 内存地址不使用时应删除。(见程序末尾的删除)
因为存储空间还没有被践踏。不要指望那种行为。
你只是返回一个内存地址,这是允许的,但可能是一个错误。
是的,如果你试图解引用该内存地址,你将有未定义的行为。
int * ref () {
int tmp = 100;
return &tmp;
}
int main () {
int * a = ref();
//Up until this point there is defined results
//You can even print the address returned
// but yes probably a bug
cout << *a << endl;//Undefined results
}
It's 'Dirty' way of using memory addresses. When you return an address (pointer) you don't know whether it belongs to local scope of a function. It's just an address. Now that you invoked the 'foo' function, that address (memory location) of 'a' was already allocated there in the (safely, for now at least) addressable memory of your application (process). After the 'foo' function returned, the address of 'a' can be considered 'dirty' but it's there, not cleaned up, nor disturbed/modified by expressions in other part of program (in this specific case at least). A C/C++ compiler doesn't stop you from such 'dirty' access (might warn you though, if you care). You can safely use (update) any memory location that is in the data segment of your program instance (process) unless you protect the address by some means.