函数返回值是指针的有关问题
函数返回值是指针的问题
#include<iostream>
using namespace std;
char *GetMemory()
{
char *p;
char a[]="hello";
p = a;
return p;
}
int main()
{
char *str=NULL;
str=GetMemory();
cout<<*str<<endl;
return 0;
}
#include<iostream>
using namespace std;
char *GetMemory()
{
//char *p;
char a[]="hello";
// p = a;
// return p;
return a;
}
int main()
{
char *str=NULL;
str=GetMemory();
cout<<*str<<endl;
return 0;
}
解释一下这两者的区别,C++中说不能返回局部变量的指针,该怎么样解释?
------解决方案--------------------
首先,这两段代码没有区别。
定义一个数组时,数组的名称实际上就是数组第一个元素的起始地址。所以以上二者性质一样。
可以通过调试器,查看main中 str的值和 GetMemory函数中a的值是否一致即可得到验证。
第二,返回局部变量的地址,这种行为的结果是未定义的。关键是,局部变量是在栈中定义的,这部分内存经常被重复使用。常见场景是方法、函数调用。一旦你调用另一个方法,很可能原来方法中返回的栈位置就被覆盖了。但如果期间没有其它方法调用,很可能结果又是正确的。至于具体会发生什么,C++标准没有做任何规定。可能有些编译器为了提高代码正确性,做了非常严格的约束——当函数返回时,对用过的栈内存做清零或随机化赋值处理,以保证你的代码不依赖于这种未定义的行为。所以,不能返回局部变量的指针。
至于栈的具体工作原理,大致如下:
程序运行时,分配了一段固定大小的内存作为栈空间使用,并维护一个栈顶指针(sp)用于标识可用栈空间从那个位置开始。每调用一个方法,都会将该方法固定需要的上下文(包括返回时的指令地址(ip),参数内容等)依次存入栈内。并且该方法中如果有定义局部变量,则依定义次序,分别从栈中分配对应的空间供其使用。在方法完成时(return),根据栈空间的分配情况,获取一开始入栈的ip,并调整sp值,使其恢复到方法调用前的位置(就好像每调用过这个方法一样)。最后根据ip值开始执行下一条指令。
这就是汇编指令的执行原理。注意,函数返回时,只是调整了栈顶指针值,而没有对“被抛弃”的栈空间做任何处理。所以,理论上,该控件依旧保留了被调方法中所定义的局部变量内容。但是如果再调用一个方法,则会出现前面提到的栈空间被覆盖的情况。所以,这种行为不安全!
------解决方案--------------------
#include<iostream>
using namespace std;
char *GetMemory()
{
char *p;
char a[]="hello";
p = a;
return p;
}
int main()
{
char *str=NULL;
str=GetMemory();
cout<<*str<<endl;
return 0;
}
#include<iostream>
using namespace std;
char *GetMemory()
{
//char *p;
char a[]="hello";
// p = a;
// return p;
return a;
}
int main()
{
char *str=NULL;
str=GetMemory();
cout<<*str<<endl;
return 0;
}
解释一下这两者的区别,C++中说不能返回局部变量的指针,该怎么样解释?
------解决方案--------------------
首先,这两段代码没有区别。
定义一个数组时,数组的名称实际上就是数组第一个元素的起始地址。所以以上二者性质一样。
可以通过调试器,查看main中 str的值和 GetMemory函数中a的值是否一致即可得到验证。
第二,返回局部变量的地址,这种行为的结果是未定义的。关键是,局部变量是在栈中定义的,这部分内存经常被重复使用。常见场景是方法、函数调用。一旦你调用另一个方法,很可能原来方法中返回的栈位置就被覆盖了。但如果期间没有其它方法调用,很可能结果又是正确的。至于具体会发生什么,C++标准没有做任何规定。可能有些编译器为了提高代码正确性,做了非常严格的约束——当函数返回时,对用过的栈内存做清零或随机化赋值处理,以保证你的代码不依赖于这种未定义的行为。所以,不能返回局部变量的指针。
至于栈的具体工作原理,大致如下:
程序运行时,分配了一段固定大小的内存作为栈空间使用,并维护一个栈顶指针(sp)用于标识可用栈空间从那个位置开始。每调用一个方法,都会将该方法固定需要的上下文(包括返回时的指令地址(ip),参数内容等)依次存入栈内。并且该方法中如果有定义局部变量,则依定义次序,分别从栈中分配对应的空间供其使用。在方法完成时(return),根据栈空间的分配情况,获取一开始入栈的ip,并调整sp值,使其恢复到方法调用前的位置(就好像每调用过这个方法一样)。最后根据ip值开始执行下一条指令。
这就是汇编指令的执行原理。注意,函数返回时,只是调整了栈顶指针值,而没有对“被抛弃”的栈空间做任何处理。所以,理论上,该控件依旧保留了被调方法中所定义的局部变量内容。但是如果再调用一个方法,则会出现前面提到的栈空间被覆盖的情况。所以,这种行为不安全!
------解决方案--------------------