内部、外部函数变量的作用域和存储方式及函数应用
一 、课前知识提前学习
1、局部变量和全局变量
局部变量和全局变量
根据变量的声明方式将变量分为局部变量和全局变量。
(1)局部变量
在一个函数内部或复合语句块内定义的变量称为局部变量,其作用域仅限于函数内或复合语句块内。 根据函数的定义,一个函数内部定义的变量或函数的形式参数,与其他函数定义的变量之间没有关系,只能被当前函数的语句使用。当前函数也不能使用其他函数的局部变量。例如:
int func1(int a,int b) int func2( ) main()
{ { {
int i; int i; int i, j;
} } }
其中,func1函数的局部变量是形式参数a和b以及变量i;func2函数的局部变量是变量i;main函数的局部变量是变量i和j。虽然func1,func2和main函数中都有一个整型的变量i,但因它们属于不同的函数,占据不同的内存单元,互相并不影响。
编译系统开始并不为局部变量分配内存,只有在程序运行过程中,需要调用局部变量所在的函数时,才临时分配内存空间,调用结束后立即释放空间。
(2)全局变量
所有函数(包括main函数)之外声明的变量称为全局变量,其作用域是从定义的位置开始到本源程序文件结束。根据C语言“先声明后使用”的原则,如果试图在全局变量定义前使用它,将会导致编译出错。
声明格式: [extern] 数据类型 全局变量名列表;
例如:
void func1()
{
extern int gn; /*确定gn在其它位置定义,是一个合法的全局变量*/
gn=1;
}
int gn; /*定义全局变量gn*/
main()
{
func1();
}
编译器在编译func1内的gn=1语句之前,根据extern int gn已知道gn在其他位置定义,是合法的全局变量。使用extern对外部变量声明只是表明在该函数内或复合语句内要使用外部变量。由于全局变量在定义时就分配内存空间,可以在定义的同时赋初值。 例如:
int gn=10;
在一个源程序中,全局变量和局部变量可以同名,在局部变量有效的范围内,全局变量不起作用。
一般来说,全局变量的定义总是放在源文件的首部,可以避免函数内部进行extern声明,声明位置后的函数都可以使用该全局变量。例如: /*全局变量gnNum定义源文件开始处,对后面的函数都有效*/
[extern] intgn;
void func1()
{
gn=1;
}
main()
{
func1();
}
如果省略extern,外部全局变量的作用域只能是当前.C文件。
如果只希望在当前文件内使用而不允许其它文件访问一个全局变量,需要将其显式声明为内部全局变量。
声明格式:static 数据类型 全局变量名列表;
例如:
static int gnVar=1;
使用static全局变量可以增强源文件的独立性,不同文件的static全局变量互不影响,有助于源文件的移植。这些特点对于较大的程序是很有必要的。
全局变量方式破坏了函数的封装性能,还可使函数代码的可读性降低。因此,如果没有必要的话,最好不要使用全局变量。
2、变量的存储类型
变量的存储类型
程序运行后,内存中可供使用的存贮空间分为代码区(用于存放程序的二进制代码)、静态存贮区和动态存贮区三个部分,与程序相关的数据(变量)存放于静态存贮区和动态存贮区中。
存储在静态存贮区的变量称为静态变量。特点是在变量定义时就从静态存贮区内分配存储单元并一直保持,直至程序结束释放该变量(例如全局变量)。
存储在动态存贮区的变量称为动态变量。特点是在程序运行期间,根据需要随时在动态存贮区内分配存储单元,使用结束后马上释放该变量的内存空间(例如函数的形参)。
根据变量在内存中的存储位置,变量有auto、static、register等存贮类型。
(1)auto类型
auto类型变量存储在动态存贮区中,为动态变量,只在定义的函数内有效。
语法格式:[auto]数据类型 变量名[=初始化值];
例如:
auto int a=10; 或 int a=10; /* auto可以省略*/
若没有为在函数体内定义的变量赋初值,则其初值随机。局部变量都是auto型变量。当函数被调用时,系统为该函数的局部变量分配内存,当调用过程结束,系统释放所有该函数的局部变量。动态变量的生存期是从其声明开始到其所在的语句块结束。
(2)registe类型
register变量存放在CPU的寄存器中。当需要使用register变量时,无须访问内存,直接从寄存器中读写。
语法格式:register数据类型 变量名;
例如:
register 数据类型 变量名;
register变量只能是int、char或指针型。auto局部变量都可以做为register变量。全局变量和静态变量不能定义为register变量。由于CPU寄存器容量有限,不能定义太多的register变量。
(3)static类型
静态局部变量在函数调用结束后,其值仍然存在,并可能影响到下一次调用的过程。
声明格式:[static]数据类型 变量名;
例如:
static int b=10;
静态类型变量(静态变量)分为静态局部变量和静态全局变量。
static局部变量是一种比较特殊的局部变量。它的作用域只能是当前的函数,其他函数不能引用它;但是存放在静态存贮区,其生存期从程序开始运行,知道程序结束后才被释放。利用static局部变量的特点,可以保存上次函数调用的某些结果。但是使用static局部变量会导致函数的多次调用之间发生联系,使代码的可读性降低。
静态全局变量既是内部全局变量,只作用于定义它的源文件,同一源程序的其他源文件不能对其使用。不论是否有static声明,该全局变量都存放在静态存贮区,生存期都是相同的。
static局部变量和auto局部变量对初值的处理不同。如果一个auto变量在定义时没有赋初值,那么它是一个随机值;如果没有对static局部变量赋初值,编译器将自动将其赋值为0(对于数值型变量)或空字符(对于字符型变量)。
3 、变量的生存期与作用域
变量的生存期与作用域
变量的生存期是指变量声明开始到其所占用内存空间被收回的全过程。变量的作用域是指变量所作用的范围。生存期和作用域变量体现了变量的特性,生存期表现了变量存在的时间,而作用域表现了变量活动的空间。两者既有关联,又有区别。例如:全局变量声明在函数外部。其生存期与应用程序的生存期相同。全局变量的作用域与其所在位置有关系,从其声明开始到所在的源程序结束。动态局部变量的生存期与其所在的语句块或函数有关系,其作用域为其所在语句块或函数体。静态局部变量的生存期与应用程序的生存期相同,其作用域为其所在语句块或函数体。
4、内部、外部函数
当一个程序由多个源文件组成时,如果一个函数可以被其他源文件调用,该函数就称为外部函数;如果一个函数只能被本文件中的函数调用,该函数就称为内部函数。
(1)外部函数
定义外部函数时,在函数名和函数类型之前加extern,表示可供其他函数调用,extern也可省略。
定义格式:[extern] 函数类型 函数名(形式参数)
例如:
extern int Add(int a,int b)
{
return a+b;
}
事实上,前面知识点所介绍的函数均为外部函数。
( 2)内部函数
定义内部函数时,只需在函数名和函数类型之前加static。
定义格式:static 函数类型 函数名(形式参数)
内部函数又称静态函数。使用内部函数,可以使函数仅局限于所在的文件,因而在不同文件中可以定义相同名称的内部函数而相互不干扰。