01 – 变量的作用域和生命周期
上一文我们从上帝的视角去看变量,看透了变量的本质,是一段有定义、有意义和可变的内存,这仅仅是她的语法和语义,落实到编程中,她是程序员进行创建和调用的,既然能在代码这个大千世界里面担任重要的角色,那么她就一定有属于自己的魅力之处,作用域和生命周期便是她的自我修养。变量的自我修养非常重要,她关乎到代码的设计,老规矩,我们先抛出几个问题:
1、超过了作用域,生命周期的作用是什么?
2、程序能知道变量的生命周期结束了吗?
3、生命周期是动态的还是静态的?
要搞清这些问题,必须先知道作用域和生命周期的本质是什么,知道本质方可解题。
02 – 变量的作用域
作用域:能够通过变量名去访问这个变量的区域
注意作用域强调的一定是通过变量名进行访问,通过指向变量的指针不算,干涩难懂?举个例子:
int* IncAndGetVar(void)
{
static int Num = 0;
Num++;
return &Num;
}
void Func(void)
{
int* pVar = IncAndGetVar();
*pVar += 2;
}
复制代码
以上代码中,变量Num的作用域仅仅是IncAndGetVar函数内部,在Func()函数中没有Num的作用域。因为Num是IncAndGetVar()函数的静态局部变量,Num这个变量名只在函数内可见,因此Num的作用域只在IncAndGetVar()函数内,即使Func()函数得到了Num的地址并且改变了Num的值,但是并非使用变量本身的名字进行操作,所以超出了IncAndGetVar(),就超出了变量Num的作用域。这里可以得出一个结论:超出了作用域,也能访问到变量(通过地址),前提是生命周期依然存在。
知道本质后,关于什么全局静态、局部静态、全局自动变量等等的作用域还需要去背吗?不需要了,可以看名字就推导出作用域:
全局自动变量:只要声明了该变量(extern xxx)和定义它的本文件且不存在同名的局部变量区域内,都是它的作用域,可以理解为工程内所有区域,如果全局和局部同名时,操作局部会屏蔽全局
全局静态变量:只在定义它的文件且不存在同名的局部变量区域内,因为静态原因,其变量名其它文件不可见,同时如果全局和局部同名时,操作局部会屏蔽全局
……
03 – 变量的生命周期
生存期:能够访问这个变量的时间段
注意生命周期强调的是能够访问,访问有2种,1是变量名,2是指针,只要其中一种能够访问并且有效,那么生命周期就存在,于是判断变量的生命周期是否存在,就取决于它是否在内存有效,还是上面的例子:
int* IncAndGetVar(void)
{
static int Num = 0;
Num++;
return &Num;
}
void Func(void)
{
int* pVar = IncAndGetVar();
*pVar += 2;
}
复制代码
变量Num的生命周期是整个程序运行阶段都存在的,因为它是局部静态变量,只要程序在运行,它就存在于内存当中,在内存有效,就有办法去访问它。
变量pVar的生命周期是Func()函数的内部,因为它是局部自动变量,函数Fcun调用结束后,pVar的空间将被编译器释放,一旦释放,此变量在内存就没有一席之地了,也就是无效,变量在内存中无效后,生命周期就随之结束。
随后会有一个疑问,如果Num是局部自动变量呢?也就是下面:
int* IncAndGetVar(void)
{
int Num = 0;
Num++;
return &Num;
}
void Func(void)
{
int* pVar = IncAndGetVar();
*pVar += 2;
}
复制代码
这样子学过C指针的估计都知道,这样程序一旦运行就可能会崩溃,因为局部自动变量在函数调用结束后,它的生命周期就结束了,本来它所占用的位置会被其他人占用,也就是它在内存已经无效,不能再去访问它。
04 – 回答问题
1、超过了作用域,生命周期的作用是什么?
超过了作用域,如果生命周期依然存在的话,生命周期的作用是让变量始终在内存有效,等着被访问,不能消失,就像站着茅坑不拉屎一样。
2、程序能知道变量的生命周期结束了吗?
不能知道,因为无法知道内存是否有效。
3、生命周期是动态的还是静态的?
是动态的,函数被调用的时候,局部变量生命周期存在,函数结束的时候,局部变量生命周期消失。