C++ 变量根据定义的位置的不同的生命周期,具有不同的作用域,作用域可分为 6 种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。
从作用域看:
全局变量具有全局作用域。全局变量只需在一个源文件中定义,用extern就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。
静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。
静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。
从分配内存空间看:
全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。(动态分配内存在堆区)
- 1)、静态变量会被放在程序的静态数据存储区(数据段)(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
- 2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。
Tips:
- A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
- B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
- C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
- D、如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
- E、函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
静态函数 :在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件
如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,这种函数也称为内部函数。
1、一个函数体内可以存在重名的变量,前提是它们的作用域不同
#include <iostream>
using namespace std;
int main()
{
int b = 2;
{ //{}为一个作用域
int b = 1;
cout << "b = " << b << endl;//输出 "b = 1"
}
cout << "b = " << b << endl;//输出"b = 2"
}
2、全局变量
1)全局变量的值可以在局部函数内重新赋值
2)全局变量从定义处开始至程序结束起作用,即全局变量存在有效作用域。
#include <iostream>
using namespace std;
int g = 20;// 全局变量声明
void add(int a,int b)
{
g=a+b;
}
int main(){
add(10,20);
cout<<g<<endl;//输出"30"
//cout<<a<<endl;//编译错误,全局变量存在有效作用域
return 0;
}
int a = 10;
3、静态全局变量
#include <iostream>
using namespace std;
static int a = 20;// 全局变量声明
void fun1()
{
cout<<"a = "<<a--<<endl;
}
void fun2()
{
static int b = 10; //第一次进入该函数声明并初始化b=10;后面进入不再重声明,而是引入上次的b
cout<<"b = "<<b--<<endl;
}
int main()
{
for (int i=0; i<10; i++)
{
fun1();
}
for (int i=0; i<10; i++)
{
fun2();
}
return 0;
}