7.5.2 全局变量
前面说过,程序的编译单位是源程序文件,一般来说,一个项目通过编译、链接后就会生成一个.exe可执行文件,而一个项目由一个或多个源程序文件组成。例如,MyProject.cpp就是一个源程序文件,一个源程序文件内可以包含一个或多个函数,如main函数,前面范例中还定义了一个func1函数等。
刚刚讲过,在函数内定义的变量叫局部变量。那么在函数外定义的变量就称为全局变量(也叫外部变量)。全局变量可以为本源程序文件中其他函数所共用(全局变量还可以被其他源程序文件所用,后续会讲解),它的有效范围从定义该变量的位置开始到本源程序文件结束为止,如果在整个源程序文件开头定义该变量,则整个文件范围内都可以使用该全局变量。看看如下范例:
这里p,q,c1,c2都是全局变量,但作用范围不同,因为它们定义的位置不同,作用范围都是从变量定义的位置开始到整个源程序文件末尾。既然作用范围不同,那么,上面的代码中,在main函数和f2函数中可以使用全部4个全局变量,而在f1函数中只能使用全局变量p和q,不能使用全局变量c1和c2(因为c1、c2定义在f1函数的下面)。总体来说就一句话:
一个函数中,既可以使用本函数中定义的局部变量,也可使用有效的全局变量。
那看一看全局变量的优缺点。
(1)优点。增加了函数与函数之间数据联系的渠道。如果一个函数中改变了全局变量的值,就能影响到其他使用到该全局变量的函数,相当于在各个函数之间有了直接的传递数据的通道,不需要再通过实参、形参来传递数据了。因为C语言中函数只能返回一个值(无法一次返回多个值),所以如果使用了全局变量,也就相当于能够从函数中返回多个值了。
(2)缺点。
①只在必要的时候才使用全局变量(谨慎使用),因为全局变量在程序整个执行期间一直占用着内存,而不像函数内的局部变量,当函数执行完毕后,这些局部变量所占的内存会被系统释放(回收)。
②降低了函数通用性,因为函数执行时可能要依赖这些全局变量,如果将函数迁移到另一个源程序文件中时,与该函数相关的全局变量也需要考虑迁移问题,并且如果迁移到的目标源程序文件中也有同名的全局变量,就比较麻烦。
③到处是全局变量,降低了程序的清晰性和可读性。读程序的人难以清楚地判断每个瞬间每个全局变量的值(因为很多函数都能改变该全局变量的值)。
所以,要限制使用全局变量。
这里做一个全局变量的演示。看看如下范例:
有几点说明:
(1)如果某个函数想引用在它后面定义的全局变量,可以使用关键字extern做一个“外部变量说明”,表示该变量在函数的外部定义,这样在函数内就能使用,否则编译就会出错,但有一点要注意,全局变量在定义的时候是可以给初值的,但是在做外部变量说明时,是不可以给变量初值的。看看如下范例:
所以,容易想到,如果全局变量的定义放在引用它的所有函数之前,就可以避免使用关键字extern做外部变量说明了。
(2)严格区分全局变量(外部变量)定义和外部变量说明。全局变量定义只能有一次,位置是在所有函数之外,定义时会分配内存,定义时可以初始化该全局变量的值。
而在同一个文件中,外部变量说明是可以有很多次的(不分配内存)。在上面的范例中,是把外部变量说明放在文件最上面,所有函数之外。其实在每个函数内部做外部变量说明也是可以的(不过一般极少看到有人这样做),所以这更进一步加深了对外部变量说明的理解:所声明的变量是已在外部定义过的变量,仅仅是引用该变量而做的“声明”。看看如下范例:
(3)在同一个源文件中,如果全局变量和局部变量同名,则在局部变量作用范围(作用域)内,全局变量不起作用,如果给局部变量赋值,当然也不会影响全局变量的值。看看如下范例:
(4)针对一个项目中包含多个源程序文件的情形(后面会详细讲解如何在一个项目中包含多个源程序文件),如果在一个源程序文件中定义的全局变量想在该项目的其他源程序文件中使用,则只需要在其他的源程序文件中使用上面介绍的extern关键字做外部变量说明,就可以在其他源程序文件中使用该全局变量了。
例如,在MyProject.cpp中定义了一个全局变量:
假设要在MyProject2.cpp(后面会讲一个新的.cpp源程序文件如何加入到当前项目中来)中的func1函数内使用MyProject.cpp中定义的全局变量a,则首先在MyProject2.cpp的开头使用关键字extern对全局变量a做外部变量说明(表示这个变量在其他文件中已经定义了),然后就可以开始使用了。MyProject2.cpp的代码如下: