必备技能7.3:静态变量
静态变量在其函数或者文件中是永久性的变量。它们和全局变量不同的是,在其在所在的函数或者文件之外,它们是不被感知的。static 对全局变量和局部变量的影响是不一样的,因此我们将分别讨论这两种情况。
静态的局部变量
当static修饰局部变量的时候,变量将被分配一个永久性的存储空间,这点和全局变量时一样的。这样一来,静态的局部变量在函数被多次调用之间是能保持其职的。(也就是说,它的值不会在函数返回的时候丢失,这点不像普通的局部变量。)静态的局部变量和全局变量的主要区别就是:静态的局部变量只能在声明他的代码块中被感知。
声明静态局部变量的方式就是在它类型的前面加上static关键字。例如,下面的语句声明变量count为一个静态的变量:
static int count;
我们也可以在声明静态变量的时候对其进行初始化。例如,下面的语句就是初始化静态变量count为200:
static int count = 200;
静态变量只会在程序开始执行的时候进行一次初始化,而不是每次在进入他所在的代码块的时候都进行初始化。
对于那些在被多次调用之间必须保持变量值的函数来说,静态局部变量时至关重要的。假设此时我们不使用静态的局部变量,那么我们就只能使用全局变量了,使用全局变量会产生一些副作用的。
下面的程序就是静态局部变量的一个示例。他用来计算用户输入的数值的平均值。
- //计算用户键入数值的平均值
- #include <iostream>
- using namespace std;
- int running_arg(int i);
- int main()
- {
- int num;
- do
- {
- cout << "Enter numbers ( -1 to quit): ";
- cin >> num;
- if ( num != -1 )
- {
- cout << "Running average is : " << running_arg(num);
- }
- cout << "\n";
- }while(num > -1);
- return 0;
- }
- int running_arg(int i)
- {
- //由于sum和count都是静态的局部变量,所以函数
- //running_arg()被多次调用之间,它们的值是会被保留的。
- static int sum = 0, count = 0;
- sum = sum + i;
- count++;
- return sum / count;
- }
静态的全局变量
当我们在声明全局变量的时候,如果加了static关键字,就是要告诉编译器这个全局变量只能被它所在的文件中的代码所感知。这就意味着,尽管这个变量是全局变量,但是其它文件中的代码是不能感知到这个变量的,更不能修改这个变量的值。这样就消除了全局变量的作用。因此,对于那些极少数的,局部变量不能完成所需功能的情况下,我们就可以创建一个小的文件,其中只包含那些需要使用全局静态变量的函数,对其进行单独的编译后就可使用了,而不用考虑全局变量带来的副作用了。在这里,我们重写了上面的用来计算平均值的程序,作为演示静态全局变量的例子。我们把程序分为两个文件,还增加了函数reset()用来对对平均值进行清零。
文件1:
- #include <iostream>
- using namespace std;
- int running_avg(int num);
- void reset();
- int main()
- {
- int num;
- do
- {
- cout << "Enter numbers ( -1 to quit, -2 to rest ): ";
- cin >> num;
- if ( num == -2)
- {
- reset();
- continue;
- }
- if ( num != -1 )
- {
- cout << "Running average is: " << running_avg(num);
- }
- cout << "\n";
- }while(num != -1);
- return 0;
- }
文件2:
- static int sum = 0, count = 0; //静态的全局变量只有在声明其的文件中才能被感知
- int running_avg(int i )
- {
- sum = sum + i;
- count++;
- return sum / count ;
- }
- void reset()
- {
- sum = 0;
- count = 0;
- }
这里,sum和count都是全局的静态变量,它们仅限于文件2中。因此它们可以被文件2中的running_arg()和reset()函数访问,但是不能被其它文件中的代码访问。这也使得通过reset()函数可以重置它们的值,以便对下一组的数据进行平均值的计算。然而,除了文件2之外的函数都是不能访问这两个变量的。例如,当我试图在文件1中访问sum和count这两个变量的时候,编译器就会报告错误。
复习一下:局部的静态变量只能被在它被声明的待模块或者函数中被感知;全局的静态变量也只能被其所在的文件所感知。本质上,static修饰字使得变量在需要的范围里可以被感知,避免了可能的副作用。static类型的变量使得我们程序员能够把程序的一部分对其它部分隐藏起来。这对于大型程序的管理来说是一个很大的帮助。
问专家:
问:我听说有些C++程序员不使用静态的全局变量,是这样吗?
答:尽管静态的全局变量目前是有用的,并且也在C++代码中存在着广泛的应用,但是C++标准并不鼓励这样做。它们推荐使用另外的一种用于对全局变量进行访问权限控制的机制:命名空间。本书的后续章节会对这点进行介绍。然而,C程序员会大量使用这样的静态全局变量,这是因为C语言不支持命名空间。正是由于这些原因,我们还是会在很长的一段时间内看到静态全局变量的出现。