第六章函数
2
6.3 变量的作用域作用域是某些事物起作用或有效的区域。
限于陆地限于海洋限于空中
3
程序中变量也有不同的使用范围,称为变量的作用域。变量的作用域决定变量的可访问性
6.3 变量的作用域
void displayDiscount()
{
float discount_amt;
.,,
.,,
.,,
}
局部变量:不能在函数外使用
float discount_amt;
void main()
{
.,,
.,,
}
void displayDiscount()
{
.,,
.,,
}
全局变量:可以在整个程序中使用
6.3.1 局部变量
内部变量,在一个函数内部定义的变量称内部变量。它只在本函数范围内有效,
即:只有在本函数内才能使用这些变量,
故称为“局部变量” 。
例:
float f1( int a) /* 函数 f1 */
{int b,c;
… /* a,b,c有效 */
}
char f2(int x,int y) /* 函数 f2 */
{int i,j; /* x,y,i,j有效 */
}
void main( ) /* */
{int m,n;
… /* m,n有效 */
}
(1)主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。
主函数也不能使用其他函数中定义的变量。
(2) 不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。
(3) 形式参数也是局部变量。
(4) 在一个函数内部,可以在复合语句中定义变量,
这些变量只在本复合语句中有效,这种复合语句也称为,分程序,或,程序块,。
#include <stdio.h>
main()
{ int i=2,j=3,k; /*主函数体内定义的局部变量 */
k=i+j;
{ int k=8; /*复合语句定义的局部变量 */
printf("k=%d\n",k);
}
printf("k=%d\n",k);}程序执行结果为:
k=8
k=5
6.3.2 全局变量
外部变量,函数之外定义的变量称为外部变量。外部变量可以为本文件中其他函数所共用。 它的有效范围为从定义变量的位置开始到本源文件结束 。所以也称全程变量。
建议:不必要时不要使用全局变量,原因如下:
① 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。
② 使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值,程序容易出错。因此,要限制使用全局变量。
③ 降低函数的通用性。因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。
但若该外部变量与其他文件的变量同名时,就会出现问题,降低了程序的可靠性和通用性。一般要求把C程序中的函数做成一个封闭体,除了可以通过
“实参 ——形参”的渠道与外界发生联系外,没有其他渠道。
外部变量与局部变量同名
#include <stdio.h>
int a=3,b=5; /* a,b为外部变量 */ a,b作用范围
void main ( )
{ int a=8; /*a为局部变量 */ 局部变量 a作用范围
printf (″%d″,max (a,b)); 全局变量 b的作用范围
}
max (int a,int b) /*a,b为局部变量 */
{ int c;
c=a> b?a∶ b; 形参 a,b作用范围
return (c);
}
运行结果为 8
12
变量的作用域
#include <stdio.h>
void addNumbers()
{
int num1,num2,sum;
printf("\n 请输入两个数,");
scanf("%d %d",&num1,&num2);
sum=num1+num2;
printf(" 子函数中 sum 的值是 %d \n",sum);
}
void main()
{
int sum=0;
addNumbers();
printf("\n 主函数中 sum 的值是 %d \n ",sum);
}
内存
sum
num20
45
num1
请输入两个数,56 45
子函数中 sum的值是 101
主函数中 sum的值是 0
56
sum
101
13
变量的作用域
#include <stdio.h>
int sum=0;
void addNumbers()
{
int num1,num2;
printf("\n 请输入两个数,");
scanf("%d %d",&num1,&num2);
sum=num1+num2;
printf(" 子函数中 sum 的值是 %d \n",sum);
}
void main()
{
addNumbers();
printf("\n 主函数中 sum 的值是 %d \n ",sum);
}
内存
sum
num20
45
num1
请输入两个数,56 45
子函数中 sum的值是 101
主函数中 sum的值是 101
56
101
14
6.4 变量的存储类别
变量的存储方式可分为“静态存储”和“动态存储”两种
静态存储变量是一直存在的,而动态存储变量则时而存在时而消失
这种由于变量存储方式不同而产生的特性称为变量的生存期
生存期表示了变量存在的时间
6.4 变量的存储类别
C程序运行时占用的存储空间通常分为 3个部分:程序区、静态存储区和动态存储区。程序区存放的是可执行程序的机器指令;静态存储区中存放的是需要占用固定存储单元的变量,
如全局变量等;动态存储区存放的是不需要占用固定存储单元的变量,如函数形式参数等 。
在 C语言中变量的定义包括 3个方面的内容:
1,变量的数据类型。如 int,char,float等;
2,变量的作用域,即变量的作用范围。如上节介绍的局部变量、全局变量的作用范围;
3,变量的存储类别。这是变量的另一个重要属性
从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。
从变量值 存在的时间角度来分,变量的存储类别分为两类:动态存储类别和静态存储类别。
动态存储类别的变量指的是这样一种类型的变量:
预先不分配存储单元,当程序运行期间进入定义它的函数或复合语句时,才分配存储空间,离开时所占存储空间被释放 。 典型的例子是函数的形式参数
,在函数定义时并没有给形参分配存储单元,只在函数被调用时才分配存储单元,函数执行完毕后,
立即释放 。
静态存储类别的变量指的是:在变量定义时就分配存储空间,并一致保持不放,直到整个程序运行结束 。 如前面介绍的全局变量都是此种存储类别的变量 。
18
6.4 变量的存储类别存储类型 说明
auto 自动变量 C语言规定,变量定义时凡是未加存储类型说明的,均视为 auto类型。因此,如下两种定义方式的效果是等价的:
int a;
auto int a;
register 寄存器变量存放在 CPU的寄存器中。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。
static 静态变量 在程序执行时存在,并且只要整个程序在运行,就可以继续访问该变量。
extern 外部变量 作用域是整个程序,包含该程序的各个文件。
生存期非常长,它在该程序运行结束后,才释放内存。
19
静态局部变量
静态局部变量生存期为整个源程序
静态局部变量作用域与自动变量相同,即只能在定义该变量的函数内使用该变量
对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予 0值
函数被调用时,其中的静态局部变量的值将保留前次被调用的结果分析下面程序中 auto变量值的变化。
#include <stdio.h>
void f1()
{
int a=0;
printf(“a=%d\n”,a);
a++;
}
main( )
{
int i;
for(i=0;i<3;i++) f1();
}
程序的执行结果都为,a=0
分析:虽然 f1函数内有 a++语句,但由于 a为 auto变量,因此每次调用 f1函数,都重新为 a分配存储单元,并被赋初值 0,每次调用结束,a所占用的存储单元都被释放,因此输出结果总是 0。
修改上例 f1函数中的 a为静态局部变量,再观察运行结果。
void f1()
{
static int a=0; /*定义静态局部变量 a*/
printf(“a=%d\n”,a);
a++;
}
main同上例(此处略)。
程序执行结果为:
a=0
a=1
a=2
分析:由于 a为静态局部变量,只在编译时赋了一次初值,
以后每次调用结束后都保留了本次运算的结果,所以输出结果依次为 0,1,2。
求 sum = 1! +2! +3! +4! +5!的值
#include <stdio.h>
int fac(int n)
{ static int f=1; /*定义静态局部变量 f*/
f=f*n;
return(f);}
main( )
{ int i,sum;
for(i=1;i<=5;i++) sum+= fac(i)
printf("sum=%d\n",sum);}
程序执行结果为:
sum=153
分析,f为 fac函数体内的静态局部变量,在编译时赋初值 1,
每次调用时都在此初值基础上乘上形参变量 n的值。 Main函数传递给 fac的实参为 i (1到 5),相当于每次返回 i的阶乘
24
函数形参和实参
void main ( )
{
.,,
.,,
display ( 10,20.5 );
}
display ( int num,float fraction )
{
.,,
.,,
}
实际参数函数调用形式参数
25
void main()
{
int a = 0; //初始化 a值为 0
func(a); //调用函数 func
printf("%d",a); //输出 a的结果
}
//定义函数 func
void func(int a)
{
a = 10; //让参数 a等于 10
}
传值调用
0
传值调用将会输出什么
26
#include <stdio.h>
void increment(int,int);
void main()
{
int num1,num2;
printf("\n 请输入两个数,");
scanf(" %d %d",&num1,&num2);
printf("\n 递增前的值是 %d 和 %d\n",num1,num2);
increment(num1,num2);
printf("\n 递增后的值是 %d 和 %d\n",num1,num2);
}
void increment(int val1,int val2)
{
val1++;
val2++;
printf("\n 子函数中值 %d 和 %d\n",val1,val2);
}
传值调用示例请输入两个数,34 56递增前的值是 34 和 56_
递增后的值是 34 和 56
num1 num2
var1
34 56
var2
子函数中的值是 35 和 57
35
34 56
57
num1 num2
34 56
34 56
FF23 FF05
调用后修改为 35 val2
FFEA FF45
将变量 num1的值赋给形参 val1
将变量 num2的值赋给形参 val2
val1 调用后修改为 57
调用函数被调用函数
27
总结 2-1
根据变量的作用域可以将变量划分为:局部变量和全局变量
根据变量的存储类型(决定生存期)将变量划分为,自动变量、寄存器变量、静态变量、外部变量
静态局部变量的生存期为整个源程序,但其作用域为定义该变量的函数
静态全局变量的生存期为整个源程序,其作用域为定义该变量的源文件
28
总结 2-2
采用传值调用方式时,在被调用函数中改变形参的值,只是改变其副本值,而不会影响调用函数中实参值
采用 引用 调用方式时,传递的是变量的地址值,
这样在被调函数中,对形参的操作实际上操作的是实参本身
数组作为函数传递时,实际 采用引用调用方式