这里不一一介绍所有变量的存放位置和生命周期,只说几讲在最近开发过程中遇到的关开局部变量的问题。
看如下的代码:
CTicTacToc::CTicTacToc()
{
CBoardAI iBoardAI(m_nPieceColor);
m_piBoardAI= &iBoardAI;
}
在构造函数中生成的一个类的对象,并将这个对象的地址传入到成员变量m_piBoardAI中。然后在其后用m_piBoardAI访问 iBoardAI的成员函数。
这是一个典型的buger,这是因为在构造函数中生成了一个临时变量,在构造函数退出后这个成员变量会被释放掉。是的,m_piBoardAI是不会被释放,但是它指向的内容已经被释放了,所以一访问就会崩!
针对这个问题,后来又研究了一下其它关于返回临时变量的问题。在这里把一些自己觉得有意义的东西整理下来。
//test1.c
#include <stdio.h>
char* get_str()
{
char str[] = {"hello"};
return str;
}
int main()
{
char* p = get_str();
printf("%s/n", p);
return 0;
}
/*test2.c*/
#include <stdio.h>
char* get_str()
{
char *str = {"hello"};
return str;
}
int main()
{
char* p = get_str();
printf("%s/n", p);
return 0;
}
运行结果:test2.c运行是没有问题的,也可以打印出正确的值,而test1.c却是错误的,打印出来的值和预期的完全不一样。
问题:他们都是返回了局部变量的指针,为什么会有差异呢?
原因:我们仔细看代码,发现他们只有一个地方不一样,那就是test1.c 里面str是一个数组,test2.c里面str是一个指针,原因就在这。在test2.c中str指针,其值是一个常量,而常量是放在数据段里面的,即便函数返回了,数据段里面的常量数据也还会在,直到程序结束才会消失,所以我们可以打印出来。而对于test1.c中的数组来说,它是一个局部变量,是放在栈里面的,函数返回之后,str指向的空间还是在的,如果我们打印出该数组的地址会发现地址是没有变的。那么为什么数组的内容(地址指向的内容)会变掉呢?难道是系统会把栈中的数据清除,答案是否定的,操作系统没必要这么做,下次用到这块内存还是会进行初始化的,这样做会消耗系统的资源。之所以在test1.c中打印出来数组的内容会变掉是因为printf本身是个函数,在函数调用时会进行参数的压栈,在压栈的过程中会把原来str指向的空间覆盖掉,因些也就改变了str指向的空间的值。如果我们在 get_str之后,不调用任何函数并不创建新的局部变量(严格的说是不使栈继续往下增长),这个时候str指向的内容还是没变的。
结论:指向常量的临时变量指针可以返回,这是因为这种临时变量是放在数据段里的,直到程序结束后才释放!
再来看一个返回局部变量的例子:
int test()
{
int a;
a = 5;
return a;
}
int b=test();
尽管a被销毁了,但它的副本5还是成功地返回了,这样做没有问题。
在返回局部实体的时候,如果用数据去接收 如 int b=test();
这时候会隐含的做一次拷,把test返回来的值(5)复制到b中;
这里之所以成功是因为函数返回来是值,面不是a。。。(这是我个人的理解,是不是正确,以后再去确认)。