知识要点:变量的作用域和生存期
视频:
目录
一、任务分析
二、必备知识与理论
三、任务实施
一、任务分析
有一个一维数组,内放 10 个学生成绩,写一个函数,求出平均分、最高分和最低分。
任务要求用一个函数来完成一组数据中求平均分、最高分和最低分。也就是说希望从函数得到三个结果值,除了可以得到一个函数的返回值以外,还可以利用全局变量得到另外两个值。
二、必备知识与理论
1. 变量的作用域
C语言中变量可以在三种基本位置加以定义:函数内部、函数参数中及所有函数外部,不同的定义范围决定了变量有不同的作用域。变量的作用域是变量在程序中可以有效索引、适当操作的特定区域,也就是作用范围。根据变量的作用范围不同,变量可以分为局部变量和全局变量。
(1)局部变量
局部变量也称为内部变量,该变量是在一个函数内部定义说明的,其作用域仅限于函数内有效,即只有在本函数内才能使用它们,在此函数以外是不能使用的,称之为“局部变量”。
(2)全局变量
全局变量也称为外部变量,该变量在函数外部定义说明。它不属于哪一个函数,而属于一个源程序文件,故全局变量可以为本文件中其它函数所共用。全局变量的位置可以在文件的开头所有函数之前,也可以在两函数之间,甚至在文件的末尾所有函数之后。它的作用域为:从定义变量的位置开始到本源文件结束。
关于全局变量的作用域还要说明以下几点:
(1)全局变量可加强函数模块之间的数据联系。由于同一文件中的所有函数都能引用全局变量的值,因此如果在一个函数中改变了全局变量的值,就能影响到其它函数,相当于各个函数间有直接的传递通道。由于函数的调用只能带回一个返回值,因此有时可以利用全局变量增加与函数联系的渠道,从函数中得到一个以上的返回值。
(2)建议在不必要时不要使用全局变量,因为:
①全局变量在程序的整个执行过程中都占用内存,而不是仅在需要时才开辟内存单元。
②它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。
③使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时 各个外部变量的值。在各个函数执行时都可能改变外部变量的值,程序容易出错。因此,要限制使用全局变量。
(3)在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,全局变量被“屏蔽”,即不起作用。
【例5.10】全局变量与局部变量同名。
#include <stdio.h>
int y=5;
void f1()
{ y=8; /*此处是对全局变量y赋值,f1()函数中没有定义任何变量*/
printf("y=%d\n",y);
}
main()
{ int y;
y=3;
f1();
printf("y=%d\n",y); /*输出的是main()函数中定义的局部变量y的值*/
}
程序的运行结果为:
y=8
y=3
注意,此例中定义了两个y,一个是全局变量y,定义时被初始化为5,在f1()函数中又被赋值为8,所以在f1()函数中输出的是全局变量y的值,“y=8”。一个是定义在main()函数中的局部变量y,这两个y也只是名称相同的两个不同实体。所以在main()函数中输出的y值是3。
2.变量的生存期
根据前面介绍,从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。从变量值存在的时间(即生存期)角度来分,可以分为静态存储变量和动态存储变量。
所谓静态存储方式,是指在程序运行期间分配固定的存储空间的方式。而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式。
(1)静态存储变量:存放在内存静态存储区中的变量称为静态存储变量。如果在定义静态存储变量时没赋初值,编译系统自动给静态变量赋初值为0。
(2)动态存储变量:存放在内存动态存储区中的变量称为动态存储变量。生存期和作用域是从时间和空间这两个不同角度来描述变量的特性,这两者既有联 系,又有区别,一个变量究竟属于哪一种存储方式,并不能仅从其作用域来判断,还应明确其存储类型说明。
3.变量的存储类别
C语言中的变量和函数都有两个属性:数据类型和存储类别。数据类型决定给数据分配的内存以及操作。存储类别是指数据在内存中的存放位置。对于数据类型,读者已熟悉,在定义一个变量时首先定义数据类型,实际上,还应该定义它的存储类别。变量的存储类别决定了变量的生存期以及给它分配在哪个存储区。
C语言中变量的存储类别共有4种:
(1)自动存储类型
自动变量的类型说明符为auto,这种存储类型是C语言程序中使用最广泛的一种类型。自动变量一般为函数或复合语句内定义的变量(包括形参)。C语言规定,函数内凡未加存储类别说明的变量均视为自动变量,也就是说自动变量可省去说明符auto。在前面程序中所定义的变量都是自动变量。
(2)寄存器存储类型
一般情况下,程序运行时各变量的值是存放在内存中的。如要对某变量进行访问,由控制器发出指令将该变量的值从内存中读到运算器中进行运算。如果变量在程序运行中使用非常频繁,则存取该变量要消耗很多时间,为提高执行效率,C语言允许将局部变量的值存放在CPU的寄存器中,称为寄存器变量。寄存器变量占用CPU的高速寄存器,不占用内存单元,使用时不需要访问内存,寄存器的读写速度比内存读写速度快,因此,可以将程序中使用频率高的变量(如控制循环次数的变量)定义为寄存器变量,这样可提高程序的执行速度。寄存器变量用关键字register作存储类别标识符。
(3)静态存储类型
静态变量的类型说明符是static,静态变量属于静态存储方式。
①静态局部变量:在局部变量的说明前加上static说明符就构成静态局部变量。
静态局部变量属于静态存储方式,它具有以下特点:
1)静态局部变量在函数内定义,但不像自动变量那样,在调用时存在,退出函数时就消失。静态局部变量始终存在着,数据的值有继承性,每次进行函数调用时可以保存原有数据的值,也就是说它的生存期为整个源程序。
2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能在其它的函数中使用此变量。
3)对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动 变量赋初值,不是在编译时进行的,而是在函数调用时进行的。每调用一次函数重新赋一次初值,相当于执行一次赋值语句。
4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
②静态全局变量:在函数外定义的变量若没有用static说明,则是全局变量(外部变量)。全局变量的类型说明之前再加以static就构成了静态的全局变量。
(4)外部存储类型
如果在一源文件中将某些变量定义为全局变量,而这些全局变量允许其它源文件中的函数引用,就需要把程序的全局变量告诉所有的模块文件。解决的办法是,在一个模块文件中将变量定义为全局变量,而在其它模块文件中,用extern来说明这些变量。
三、任务实施
本任务是有一个一维数组,内放10个学生成绩,写一个函数,求出平均分,最高分和最低分。
任务要求用一个函数来完成一组数据中求平均分、最高分和最低分。也就是说希望从函数得到三个结果值,除了可以得到一个函数的返回值以外,还可以利用全局变量得到另外两个值。
(1)首先是定义两个全局变量来存放最高分和最低分。
(2)自己定义一个有参函数average()用来完成求10个学生的平均分这个功能并且将平均分作为返回值返回到main()函数中。
(3)在main()函数中调用average()函数完成任务。
程序代码如下:
#include <stdio.h>
float max=0,min=0;
float average(float array[],int n) /* 定义函数,形参为数组 */
{ int i;
float aver,sum=array[0];
max=min=array[0];
for(i=1;i<n;i++)
{if(array[i]>max) max=array[i];
else if(array[i]<min) min=array[i];
sum=sum+array[i];
}
aver=sum/n;
return(aver);
}
main() /* 主函数 */
{ float ave,score[10];
int i;
for(i=0;i<10;i++)
scanf("%f",&score[i]);
ave=average(score,10); /* 调用average函数,将得到的值赋给ave */
printf("max=%6.2f\nmin=%6.2f\naverage=%6.2f\n",max,min,ave);
}
程序的运行结果为:
99 45 78 97 100 67.5 89 92 66 43↙
max=100.00
min= 43.00
average= 77.65
可以看出array和n的值由main提供,单向传递,函数average中aver的值传回main函数,也是单向的,max和min是全局变量,它的值既可以传入函数内,也可从函数传出去。
由此可见,可利用全局变量以减少函数实参与形参的个数,从而减少内存空间以及传递数据时的时间消耗。