在标识符作用域那一节中,我们讨论了标识符的作用域。在标识符的作用域内,标识符指代声明的数据对象。作用域外,该标识符没有意义。
#include <stdio.h>
void func()
{
int n = 100;
}
int main()
{
func();
printf("%d\n", n);
return 0;
}
例如,上面的代码中,标识符n
声明在函数func
中,它的作用域从声明int n = 100
开始,直到func
函数结束。因此,函数main
中,标识符n
不代表任何数据对象。若对这段代码进行编译。编译器将报错,错误信息为:未定义标识符n
。
那我们换一种思路,在函数main
中,既然不能使用标识符来访问函数func
中的整型变量n
。那么,我们获取到整型变量n
的指针,通过指针来访问它,是否可以呢?
1. 自动变量
#include <stdio.h>
int *func()
{
int n = 100;
return &n;
}
int main()
{
int *pN = func();
printf("%d\n", *pN);
return 0;
}
在函数func
中,我们获取整型变量n
的指针,将该指针返回到函数main
。在函数main
中,使用指针来访问整型变量n
。
对代码进行编译,我们发现代码出现了一个警告。
我们再运行这段代码试试看。
运行结果好像是正常的。但是,这样做是错误的。
默认情况下,声明在代码块内的任何变量都属于自动存储类别的变量。
自动变量在程序运行到该变量声明所在的代码块时创建,离开该代码块时销毁。这一段变量存在的周期,被称作变量的生命周期或简称生命期。
离开代码块后,变量n
将被销毁。原属于变量n
的空间不再保留。
事实上,为了指明一个变量属于自动存储类别,C语言中分配了关键词auto
。你可以在变量声明前加关键词auto
,声明该变量是一个自动变量。
#include <stdio.h>
int *func()
{
auto int n = 100; // 可以省略关键词auto
return &n;
}
int main()
{
auto int *pN = func(); // 可以省略关键词auto
printf("%d\n", *pN);
return 0;
}
但是,由于默认情况下,代码块内声明的变量均为自动变量,没必要将auto
关键词写出来。因此,在C语言代码中,几乎不会出现关键词auto
。
接下来,让我们从作用域与生命期的角度分析一下变量n
:
变量n
的生命期:从包含变量n
声明的代码块开始,直到包含声明的代码块结束为止。
变量n
的作用域:从变量n
的声明开始,直到包含声明的代码块结束为止。
请注意区分作用域与生命期的区别:
作用域:
作用域为标识符对数据对象指代关系存在的区域,它是一种关联关系。
生命期:
生命期是数据对象从创建到销毁之间,数据对象存在的周期。
在前面的代码中,虽然函数func
返回了指向变量n
的指针。但是,此时变量n
的生命期已结束。该指针指向了一个已失效的空间。这种指针被称作野指针。访问野指针有可能看起来正常,有时候可能会崩溃,有时候该空间被其他地方重新利用而导致数据错乱。
由于自动变量拥有块内作用域及生命期,所以也被称作局部变量。