1、第八章 函 数,8.1 概述一个大 程序一般应分为若干个程序模块,一个模块用来实现一个 特定的功能。C程序有一个主函数和若干个函数构成。由主函数调用其它函数;其它函数也可以互相调用;同一个函数可以被一个或多个函数调用任意多次。,第八章 函数,要记住,4. 所有函数都是平行的,即相互独立的,可以相互调用,但不能相互嵌套定义。5. 从用户角度看,C语言的函数有两种:(1). 标准函数(库函数)(2). 用户自定义函数6. 从函数形式看,C语言的函数分两类:(1). 无参函数(2). 有参函数,说明: 1. 一个C程序由一个或多个源文件组成(便于分别编写和调试)2. 一个源程序有一个或多个函数组成,
2、以源文件为单位进行编译3. C程序的执行从main函数开始,main函数是系统定义的,C 程序,源文件1,源文件2,源文件n,。,源文件 i,函数 1,函数 2,函数 n,。,组织结构,void main( ) printstar( ) ;print_message( ) ;printstar( ) ;,(1),(2),(3),void print_message( ) printf(“ How do you do!n“) ; ,void printstar( ) printf(“*n“) ;,一个源文件(三个函数),例 8.1,运行结果: *How do you do !*,printsta
3、r( ) , print_message( ) 都是无参函数;main( )主函数调用这两个子函数;print_message( )被调用两次。,1. 无参函数的定义形式(括号内无参量)类型标识符 函数名( )说明部分语句其中: “类型标识符”指定函数值的类型,即函数带回来的值的类型;如果不需要带回函数值, 写上void类型标识符(空类型);“ ”内是函数体,包括说明部分和语句部分。,函数体,8.2 函数定义的一般形式,void printstar( ) printf(“*n“); ,例如:,2. 有参函数定义的一般形式类型标识符 函数名(形式参数表列)说明部分语句形式参数的说明必须写在函数体
4、的外面,括号内。函数体内用到的变量必须在函数体内进行说明,注意,int max(int x , int y) /* 形式参数说明 */ int z; /* 函数体内变量说明 */z=xy?x:y;return(z);,例如:,3. 空函数类型标识符 函数名( ) 空函数不进行任何操作例如: dummy( ) 用途:在程序中占一个位置,以后用一个编好的函数代替。 这样做,程序总的结构清晰,可读性好。,当主调函数和被调用函数之间有数据传递关系时,应定义为有参函数。在定义函数时,函数名后面括号中的变量名称为“形式参数” (简称“形参”)。在调用函数时,函数名后面括号中的表达式称为“实际参数” (简称
5、“实参”)。,8.3 函数参数和函数的值,8.3.1 形式参数和实际参数,void main( ) int a,b,c;scanf(“%d,%d“, ,函数定义,a 和 b 就是实参,x 和 y 就是形参,数据传递,运行结果: 输入: 7,8 输出: max is 8,调用函数时的数据传递。,例 8.2,1. 在定义函数中指定的形式参数,在未出现函数调用时,它们并不占内存中的存储单元,只有在发生函数调用时,函数中的形参才被分配内存单元,在调用结束后,形参所占的内存单元即被释放。2. 实参可以是常量、变量或表达式,但必须有确定的值。在调用时将实参的值赋给形参变量(数组除外),例如:c=max(3
6、,a+b);,说 明 几 点,上例中3赋给x, a+b的值赋给y.,3. 在函数定义中必须指定形参的类型。4. 实参与形参的类型必须一致。,5. 实参变量对形参变量的数据传递是“值传递“(即单向传递),实参=形参 (即在形参中建立实参的复本)只由实参传给形参,而不能由形参传回来给实参。6. 在形参表列中同时对形参进行类型说明如: int max( int x,int y) 等价于 int max(x,y) . int x,y; ,这是早期C的写法,1. 函数的返回值是通过函数中的 return 语句获得的,return语句 将被调用函数中的一个确定值带回主调函数中去。如果需要从被调用函数中带回
7、一个函数值,则被调用函数中必须包含 return 语句。如果不需要从被调用函数中带回一个函数值,则可以不要 return 语句。一个函数中可以有一个以上的 return 语句,执行到哪一个, 哪一个就起作用。例如:if(xy) return x ;else return y ;,8.3.2 函数的返回值,return 语句的形式: return (表达式);或 return 表达式;或 return;,返回表达式的值,不返回值,例如: return (z) ; 或 return z ;return (xy?x:y) ;,2. 函数值的类型应当在定义函数时用类型标识符指定函数值的类型。例如: i
8、nt max(int x, int y) - - 函数值为整型double min(double x, double y)- 函数值为双精度型C语言中规定,凡不加类型说明的函数,一律自动按整型处理。例如: int max(int x,int y) 可写成 max(int x,int y)在定义函数时对函数的类型说明一般应该和 return 中的表达式的值的类型一致。,3. 当函数值的类型和 return 语句中的表达式的值不一致时,以函数类型为准(自动进行类型转换)。,void main( ) float a , b ;int c ;scanf(“%f,%f“, ,运行结果: 输入:1.5 ,
9、 2.5 输出:max is 2,返回值类型和函数类型不一致。,当返回时,先将z的值转换成int型 然后由return带回一个整型的函数值,例 8.3,int max(float x, float y) float z; /* z是float型 */z=xy?x:y;return(z); ,4. 如果被调用函数中没有 return 语句,并不表示函数不带回函数值,而是带回一个不确定的值。使用时要注意。5. 为了明确表示函数“不带回函数值”,可以用“void”将函数定义为“无类型”(即“空类型”),这样系统就保证不使函数带回任何值。,void main( ) printstar( );void
10、printstar( )printf(“*n“);,例如:,8.4.1 函数调用的一般形式函数名(实参表列);1. 如果是调用无参函数,则没有实参表列,但是“( )”不能省略。2. 如果实参表列中包含多个实参,每个实参之间用“,”分隔。3. 实参和形参必须一一对应,即个数相等,类型一致。,void main( ) int p ;p=f (2,3) ;printf(“%d“, p) ; ,int f (int a , int b) int c ;if(ab) c=1 ;else if(a=b) c=0 ;else c= -1 ; return ( c) ; ,8.4 函数的调用,例 8.4,1.
11、 函数语句 - 把函数调用作为一个语句,这时并不要求函数带回值。例如: printstar( );2. 函数表达式 - 函数出现在表达式中,这时要求函数带回一个确定的值参与运算。例如: c = 2*max(a,b) ;3. 函数参数 - 函数调用作为一个函数的实参。例如: m=max(a , max(b, c); printf(“%d“, max(a , b) );,8.4.2 函数调用的方式,在一个函数中调用另一个函数应具备什么条件?1. 被调用的函数必须是已经存在的函数。2. 如果是使用库函数,一般还应该在程序的开头用#include命令将调用有关库函数时所需的信息包含到本程序中。例如:#
12、include #include 3. 如果使用用户自定义的函数,而且该函数与调用它的函数在同一个文件中时, 一般还应在主调函数中对被调用函数的返回值的类型作说明。说明方式:类型标识符 被调用函数的函数名( 形参类型说明);,8.4.3 对被调用函数的说明和函数原型,注意: 只对函数的返回值和形参的类型进行说明,不包括函数体。作用: 告诉系统在该函数中将要调用的某个函数的类型,便于检查。,void main( ) float add( float x , float y) ; /* 对被调函数声明 */float a , b , c ;scanf( “%f ,%f”, ,对被调函数作函数原型声
13、明。,这种函数声明称为函数原型声明, 当调用在定义之前要作函数原型声明。 如果先定义后调用,可以不作声明。,被调函数声明的另一种形式:(可以不写出变量名)float add( float , float) ;,例 8.5,C语言中还规定以下几种特殊情况可以不对被调用函数 进行类型说明:1. 如果函数值是整型或字符型时,可以不进行类型说明。2. 如果被调用函数的定义出现在主调函数之前可以不进行类型说明(因为系统已经知道了该函数的类型)。例如:,float add(float x,float y) . void main( ) float a,b,c;c=add(a,b);. ,函数定义,函数调用
14、,3. 如果在所有函数定义之前,在文件的开头,在函数的外部已说明了函数类型,则在各个主调函数中不必对所有的函数进行类型说明。,例如:,char letter( char,char); float add(float,float);void main( ) x=add(y,z);c=letter(a,b); char letter(char c1,char c2) . float add(float a,float b) . ,C语言的函数都是互相平行的、独立的,因此C语言中不能嵌套函数定义, 但可以嵌套调用函数。,main( ) .调用a函数. ,a函数.调用b函数.,b函数.,(2),(3)
15、,(4),(1),(5),(6),(7),(8),(9),8.5 函数的嵌套调用,特别注意,嵌套调用函数的例子,( 求 f(x)=x -5x +16x -80=0 )方法:1. 取两个不同的点 x1、x2,如果f(x1)和f(x2)符号相反,则在区间(x1,x2)内必有一个根;如果f(x1)和f(x2)符号相同,改变x1、x2,直到f(x1)与f(x2)异号;2. 连接f(x1)、f(x2)两点与x轴相交于x,求x,并由x求出 f(x);x1*f(x2) x2*f(x1)x = - (求x 公式)f(x2) f(x1)3. 若f(x)与f(x1)同号,则根在(x,x2)内,这时将x作为新的x1
16、;若f(x)与f(x2)同号,则根在(x1,x)内,这时将x作为新的x2;4. 重复第2、第3步,直到 |f(x)|为止。,3 2,用弦截法求方程 f(x)=0 的根。,例 8.6,功能分解: 1. 定义一个函数 f(x),用来求 f(x) 的函数值;2. 定义一个函数 xpoint(x1,x2),用来求f(x1)和f(x2)的连线与x轴的交点x;3. 定义一个函数 root(x1,x2),用来求(x1,x2)内的那个实根;这里,函数root中要调用函数 xpoint,而函数xpoint中又要调用函数f(x);,x1,x2,x,x,y,f(x2),f(x1),f(x),0,f(x)=0, 其中
17、x就是所求的根,+,-,-,#include /* 定义函数f(x) */ float f(float x) float y;y=x*x*x - 5*x*x + 16*x - 80;return(y); ,float xpoint(float x1,float x2) /* 定义函数xpoint */ float x;x=(x1*f(x2) - x2*f(x1) / (f(x2) - f(x1);return(x); ,/* 定义函数root */ float root(float x1,float x2) int i;float x,y,y1;y1=f(x1);do x=xpoint(x1,
18、x2);y=f(x);if (y*y10) y1=y;x1=x;elsex2=x; while (fabs(y)0.0001);return(x); ,/* 主函数 */ void main( ) float x1,x2,f1,f2,x;do printf(“input x1,x2“);scanf(“%f,%f“, ,main( ) root( ) xpoint( ) f( ),root( ) xpoint( ) f( ),输出根 x 结束, ,f( ),(1),(2),(3),(4),函数之间的调用关系,在调用一个函数的过程中又出现直接或间接地调用该函数本身, 称为函数的 递归调用。 C语言
19、允许函数的递归调用。,int f(int x) int y,z;. z=f(y);. return(2*z); ,例如:,int f1(int x) int y,z;.z=f2(y);.return(2*z); ,int f2(int t) int a,c;.c=f1(a);.return(2*z); ,8.6 函数的递归调用,递归调用的条件: 在有限次的调用之后结束递归调用。即: 递归必须有一个出口。递归的求解过程分为两个阶段:第一阶段: 回推, 一直回推到递归出口条件为止;第二阶段: 递推,从递归的出口开始进行递推求解,一直推算到求得所要求的值为止。,age(int n) int c;if
20、 (n=1)c=10; /* 递归出口*/elsec=age(n-1)+2;return(c); void main( ) printf(“%dn“,age(5); ,用递归调用求年龄。有5个人,第5人比第4人大2岁. . .第1个人是10岁,问第5个人几岁?,age(5)=age(4)+2,age(4)=age(3)+2,age(3)=age(2)+2,age(1)=10,age(5)=age(4)+2=18,age(4)=age(3)+2=16,age(3)=age(2)+2=14,age(2)=age(1)+2,age(2)=age(1)+2=12,注意递归出口到哪里? 出口后转向哪里?
21、,例 8.7,main( ) printf(“%d“, age(5); ,age(5) .c=age(4)+2 ; ,age(4) .c=age(3)+2 ;. ,age(3) c=age(2)+2 ;. ,age(2) .c=age(1)+2 ;. ,age(1) c=10; ,回推,递推,递归出口的转向,long int fac(int n) long int f;if(n0)printf(“data errorn“);else if (n=0 | n=1)f=1;elsef=n*fac(n-1);return(f); ,1 n=0,1n!= n*(n-1)! n1,void main(
22、) int n;long int y;scanf(“%d“, ,5!=5*4! 5!=5*24=120,4!=4*3! 4!=4*6=24,3!=3*2! 3!=3*2=6,2!=2*1! 2!=2*1=2,1!=1,fac(5) fac(4) fac(3) fac(2) fac(1) 5! 4! 3! 2! 1!,用递归调用求n!,例 8.8,用变量作为函数的参数时,实参变量对形参变量的数据传递是 “值传递”,在执行被调用函数的过程中,形参变量的值的变化 并不会改变主调函数的实参的值。,一. 数组元素做函数实参由于实参允许是表达式的形式,因此用数组元素做实参 与用变量做实参一样, 作为实参的
23、数组元素向形参变量传递数据时也是“值传递”。,8.7 数组作为函数参数,在C语言中允许将数组名作为函数参数,但这时传递的是整个数组,void main( ) int m,a2=1,2; m=max(a0,a1); /*数组元素做实参 */printf(“max=%d“,m);printf(“a0=%d,a1=%d“,a0,a1);. ,max(int x,int y) int t;if(xy) /* 两数交换 */ t=x; x=y; y=t; printf(“x=%d,y=%dn“,x,y);return(x); ,运行结果:x=2,y=1max=2a0=1,a1=2,a0、a1的输出值=?
24、 值没有改变!,例如:,void main( ) int large(int x,int y) ; int a10,b10, i ,n=0,m=0,k=0 ,f ; printf(“enter array a:n“) ; for(i=0;ibi */else if( f = =0) m+ ; /* ai = = bi */else k+ ; /* ai bi */,数组 a 和 b元素遂个比较,给出大于,小于,等于个数。,例 8.10,printf(“ab %d timen a= =b %d timen ak) printf(“array a is larger then array b n“
25、) ;else if(nk) printf(“array a is smaller than array b n“) ;else printf(“array a is equal to array b n“) ; ,large(int x,int y) int flag ;if(xy)flag=1 ;else if(xy)flag= -1 ;elseflag=0 ; return(flag) ; ,二. 数组名作函数参数用数组名作函数参数时,实参与形参都应该用数组名(或数组指针),float average(float array ) int i;float aver,sum=0.0;for
26、(i=0;i10;i+)sum=sum+arrayi; aver=sum/10;return(aver); ,定义一个函数求一个一维数组中的元素的平均值 (设元素个数是10),设数组 score10 中存放学生成绩。,void main( ) int i;float score10,aver;printf(“input 10 scores:n“) ;for(i=0 ; i 10 ; i+)scanf(“%f“, ,例 8.11,1. 用数组名作函数参数时,必须在主调函数中定义数组和被调用函数中说明数组。2. 实参数组和形参数组的类型必须一致。3. 实参数组和形参数组的大小可以不一致。,注意,4
27、. 形参数组可以不指定大小,在定义形参数组时数组名后面跟上空的“ ” 。若在被调函数中需要处理的元素个数少于实参数组的元素个数,则可以另外再设一个参数,用来表示传递数组元素的个数。,如上例 8.11 求平均,可改为:,float average(float array ,int n) int i;float aver,sum=0.0;for (i=0;in;i+)sum=sum+arrayi; aver=sum/n;return(aver); ,main( ) int i,n;float score10,aver; printf(“Enter number:“);scanf(“%d“, ,例
28、8.12,5. 数组名作函数的参数,实参数组向形参数组传递的实参数组的起始地址,(即“地址传递”) 使形参数组和实参数组共同占同一段内存单元,即形参数组不申请空间。因此,当函数被调用时,形参 数组元素的值的变化就会使实参数组元素的值同时发生变化,实参数组,形参数组,第一个元素,第二个元素,score10,a0 a1 a2 a3 a43 6 1 9 4 a0和a1,a2,a3,a4比较,最后a0和 a2交换1 6 3 9 4 a1和 a2,a3,a4比较,最后a1和a2交换1 3 6 9 4 a2和 a3,a4比较,最后a2和a4交换1 3 4 9 6 a3和 a4比较,交换1 3 4 6 9
29、排序结束,原理:(1) 在 n-1 个数中找最小的元素与 a0 交换;(2) 在 n-2 个数中找最小的元素与 a1 交换;。,用选择法 对10个数进行排序,不返回函数值。,举例说明选择法,注意,每趟参加比较的元素个数少1个!,例 8.13,void main( ) /* 主函数 */ void sort(int array ,int n) ;int i,n,a10;printf(“Enter the array:n“);for (i=0 ; i10 ; i+)scanf(“%d“, ,void sort(int array ,int n) /* 排序函数 */ int i , j , k,
30、t;for(i=0 ; in-1 ; i+) k=i ;for (j=i+1 ; jn ; j+)if (arrayjarrayk)k=j ;if( k != i) t=arrayk;arrayk=arrayi;arrayi=t; ,其中 : 每一趟在 k 中存放最小元素的下标,若k != i , 即存在比 ai 小的元素,则 ak和 ai两个元素交换,想一下:为什么 n-1 ?,想一下:为什么 n ?,三. 用多维数组作函数参数1. 多维数组元素作为实参时,与实参变量相同,只进行单向的“值传递”。2. 多维数组名作实参和形参时,实参数组和形参数组之间进行的是“地址传递”。,在函数中对形参数组
31、的定义可以指定每一维的大小, 如:fun(int array310) 也可以省略第一维的大小,但其它维的大小说明不能省略如: fun(int array 10),不合法: fun(int array ).,max_value(int array 4) int i , j , k , max ;max=array00 ;for(i=0 ; imax)max=arrayij ;return(max) ; ,求3*4矩阵中所有元素的最大值。,1 3 5 72 4 6 8 15 17 34 12,二维数组名 a,运行结果: max value is 34,void main( ) int a34=1,
32、3,5,7,2,4,6,8,15,17,34,12;printf(“max value is %dn”, max_value(a) ; ,a34,例 8.14,在C语言中,变量除了数据类型外,还有不同的存储类别。按变量的作用域和存在域可将变量分为局部变量和全局变量。,8.8 局部变量和全局变量,8.8.1 局部变量定义:在一个函数内部定义的变量,只在本函数范围内有效,也只能在本函数内使用。即作用域和存在域为函数内部。,例如: int f1(int a) int b , c ;.char f2(int x , int y) int b , c ;.main( ) int m , n ;.,a,b
33、,c 的有效范围,x,y,b,c 的有效范围,m,n 的有效范围,1. main函数中定义的变量(m,n)只在main函数中有效。2. 不同函数中可以使用相同的变量名而不会影响。例如: f1( )中的 (b,c) 和 f2( )中的(b,c)互不干扰,在内存中占用不同的位置。3. 形参也是局部变量,只在该函数中起作用。例如:f1( )中的形参 a和 f2( )中的形参(x,y)都只在函数内有效。,说 明,4. 可以在一个复合语句中定义变量,但是该变量只在这个复合语句内起作用,这种复合语句也称为“分程序”。,void main( ) int a , b ;. int c ;c=a+b ;. ,c
34、 的有效范围,a,b 的有效范围,定义:在函数之外定义的变量称为外部变量,外部变量是全局变量。用途:为本源文件中的所有函数所共享,不需要通过形参传递,即可以使用。有效范围(即作用域和存在域):从定义变量的位置开始到本源文件的结束,8.8.2 全局变量,int p=1 , q=5 ;float f1(int a) int b , c ;char c1 , c2 ;char f2( int x , int y) int i , j ;.main( ) int m , n ;,外部变量 c1,c2 的作用范围,外部变量 p,q 的 作用范围,例如:,(1)全局变量的作用是增加一个文件内的函数间的数据
35、传递,如果在一个函数中改变了全局变量的值,将会影响到使用该全局变量的其它函数。看以下程序。,说 明,float Max=0 , Min=0 ; /* 外部变量定义 */ void main( ) float average( float array ,int n) ;float ave , score10 ;int j ;for(j=0 ; j10 ;j+)scanf(“%f“, ,在一维数组中存放10个学生成绩,写一个函数,求出平均分,最高分,最低分。,例 8.15,float average( float array ,int n) int i ;float aver,sum=array0
36、;Max=Min=array0 ;for( i=1 ;iMax)Max=arrayi ;else if(arrayiMin)Min=arrayi ;sum=sum+arrayi ;aver=sum/n ;return(aver) ; ,ave score 10 Max Min,aver array n Max Min,外部变量,main 函数,average 函数,运行结果: 输入:99 45 78 97 100 67.5 89 92 66 43 输出: Max=100.0 Min=43.0 average=77.65,(2). 建议尽量不要使用全局变量,因为:1. 全局变量在程序执行的全过程
37、占用内存单元(在编译时分配空间)。2. 降低程序的通用性可读性等,因为增加了函数之间的联系。3. 会降低程序的清晰性。(3). 如果在同一个源文件中外部变量和局部变量同名,则在局部变量的作用范围内,均以局部变量使用。,外部变量和局部变量同名。,int a=3,b=5 ; max(int a,int b) int c ;c=ab?a:b ;return ( c ) ; void main( ) int a=8 ; printf(“ %d“, max(a,b) ); ,形参 (a,b)的 作用范围,局部变量a的 作用范围,外部变量a,b的 作用范围,变量b是外部变量,运行结果: 8,8 5,例 8
38、.16,(4). 由于外部变量的有效范围是从定义点到文件终了,因此,如果要在定义点之前 的函数中使用该外部变量,应在这个函数中对该外部变量作“外部变量声明”。,例如:,外部变量说明方式:extern 类型标识符 外部变量 ;,max(int x,int y) int z;return (xy?x:y); void main( ) extern int a , b; printf(“%dn“,max(a,b); int a=10 , b=5;,将main函数中的a,b 说明成外部变量,外部变量定义在 函数之后,按变量的存在时间可将变量分为:静态存储变量,动态存储变量静态存储方式是指在程序运行期间
39、分配固定的存储空间的方式;动态存储方式是在程序运行期间根据需要进行动态的分配存储空间的方式。,8.9 变量的存储类别,8.9.1动态存储方式和静态存储方式,用户使用的内存空间分为三部分:1。程序区2。静态存储区3. 动态存储区,用户区,程序区,静态存储区,动态存储区,存放数据, 分配给变量,全局变量,局部变量,C语言中数据的存储类别分为两大类:静态存储类,动态存储类 具体包含四种方式: 自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern),在静态存储区存放:全局变量。 在动态存储区存放: 函数的形参变量,局部变量。 (临时分配空间即动态分配)函数调用
40、时的现场保护和返回地址,局部变量的隐含的存储方式是自动存储类别,即auto。对这些变量的分配和释放存储空间的工作是系统自动进行。例如:,int f (int a) /* 定义函数 f, a 为形参 */ auto int b , c ; /* 定义 b,c为自动变量 */ ,即 auto int b , c ;,函数执行结束,局部变量(b,c) 和形参a所 占用的空间被释放,auto可以省掉。例如:,int f (int a) int b , c ;. ,8.9.2 auto局部变量,如果希望函数中的局部变量的值在函数调用结束后仍然保留,作为下一次 函数调用时的初始值,这时应该将该变量定义为“
41、静态局部变量”(static).,8.9.3 静态局部变量(static),f (int a) auto int b=0 ;static int c=3 ;b=b+1 ; c=c+1 ;return(a+b+c) ; ,运行结果: 7 8 9,调用 次数,调用时初值,调用结束时的值,第一次,第二次,第三次,b c b c,0 3 1 4 70 4 1 5 80 5 1 6 9,a+b+c,a222,考察静态局部变量的值。,void main( ) int a=2 , i ;for(i=0 ; i3 ; i+)printf(“%d “, f(a) ; ,例 8.17,1. 局部静态变量属于静态存
42、储类别。自动变量属于动态存储类别。,注 意 以 下 几 点,2. 局部静态变量只在编译时赋初值,以后每一次调用时的初值就是上次函数调用结束时的值(变量值具有连续性)。自动变量每次函数调用都重新赋初值。(见上例),3. 对于静态变量,如果没有赋初值,则编译时自动赋初值0 或 空格(字符)。对于自动变量,如果没有赋初值,则值是不确定的。例如:auto int x ; x值是不确定的static int y ; y值为 0,4. 局部静态变量虽然在函数调用结束后仍然存在, 但是其它函数不能引用(是函数专用的)。,当需要保留函数上一次调用结束时的值时,需要定义局部静态存储变量。一般情况下尽量少用静态存
43、储变量,因为:1) 占用较多的内存;2) 降低程序的可读性。,int fac(int n) static int f=1 ;f=f*n ;return(f) ; void main( ) int j ;for(j=1 ; j=5 ; j+)printf(“%d!=%dn“, j , fac(j) ; ,运行结果:1! =12! =23! =64! =245! =120,打印1到5的阶乘值。,例 8.18,一般情况下,变量的值是存放在内存中的,为了提高运算效率,C语言中允许 将局部变量的值存放在寄存器中,这种 变量 称为“寄存器变量“(register)。,8.9.4 register 变量,1
44、. 只有局部自动变量和形参可以作为寄存器变量,临时占用。2. 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量,不同的系统对register变量的处理是不同。( Turbo C 中虽然允许register变量,但作为auto变量处理 )3. 局部静态变量不能定义为寄存器变量,因为不能长期占用。,注 意,使用register变量求n!,int fac(int n) register int j , f=1 ; for(j=1 ; j=n ; j+) f=f*j ; return(f) ; ,void main( ) int j ;for( j=1 ; j=5 ; j+)printf(“%d! =%dn“, j, fac(j) ); ,例 8.19,全局变量存储在静态存储区,并可以为本程序文件中的所有 函数引用。(即函数共享)定义域和作用域:从变量定义开始到本程序文件结束。,8.9.5 全局变量extern的存储方式,int max(int x , int y) int z ;z=xy ? x : y ;return(z) ; void main( ) extern int A , B ;printf(“%d“, max(A,B) ); int A=13,B= -8 ;,