kj-第7章函数ppt课件(全).ppt
第第7章章 函数函数l本章概述本章概述 l本章的学习目标本章的学习目标l主要内容主要内容第第7章章 函数函数l本章概述本章概述 本章介绍函数定义的形式、调用本章介绍函数定义的形式、调用的方法、函数嵌套调用和递归调用的的方法、函数嵌套调用和递归调用的方法、数组做函数参数的使用方法、方法、数组做函数参数的使用方法、局部变量和全局变量的使用方法、变局部变量和全局变量的使用方法、变量存储类别、内部函数和外部函数等量存储类别、内部函数和外部函数等内容。内容。第第7章章 函数函数 本章教学目的:掌握函数定义的形式,调用的方本章教学目的:掌握函数定义的形式,调用的方法,掌握函数嵌套调用和递归调用的方法,掌握数组法,掌握函数嵌套调用和递归调用的方法,掌握数组做函数参数的使用方法,掌握局部变量和全局变量的做函数参数的使用方法,掌握局部变量和全局变量的使用方法,掌握变量存储类别,了解内部函数和外部使用方法,掌握变量存储类别,了解内部函数和外部函数。函数。本章教学重点:函数的定义和调用,嵌套调用和本章教学重点:函数的定义和调用,嵌套调用和递归调用,数组做函数参数,局部变量和全局变量。递归调用,数组做函数参数,局部变量和全局变量。本章教学难点:嵌套调用和递归调用,数组做函本章教学难点:嵌套调用和递归调用,数组做函数参数,局部变量和全局变量。数参数,局部变量和全局变量。本章的学习目标本章的学习目标:第第7章章 函数函数l7.1 函数概述函数概述l7.2 函数的定义函数的定义l7.3 函数的参数和函数的返回值函数的参数和函数的返回值l7.4 函数的调用函数的调用l7.5 函数的嵌套和递归调用函数的嵌套和递归调用l7.6 数组作为函数的参数数组作为函数的参数l7.7 局部变量和全局变量局部变量和全局变量l7.8 变量的存储类别变量的存储类别l7.9 内部函数和外部函数内部函数和外部函数l7.10 程序设计举例程序设计举例主要内容主要内容:7.1 函数概述l在进行程序设计时,设计人员通常把一个较大的程序在进行程序设计时,设计人员通常把一个较大的程序划分为若干个程序模块,每一个程序模块用来实现一划分为若干个程序模块,每一个程序模块用来实现一个特定的功能,通常把每个程序模块称作一个子程序。个特定的功能,通常把每个程序模块称作一个子程序。l在在C语言中,子程序的功能是由函数来完成的,一个语言中,子程序的功能是由函数来完成的,一个C程序可由一个主函数和若干个函数构成。由主函数调程序可由一个主函数和若干个函数构成。由主函数调用其它函数,其它函数也可以互相调用,同一个函数用其它函数,其它函数也可以互相调用,同一个函数可以被一个或多个函数调用任意多次。可以被一个或多个函数调用任意多次。l在程序设计中,常将一些常用的功能模块编写成函数,在程序设计中,常将一些常用的功能模块编写成函数,放在函数库中供编程时选用。在程序设计时,如果能放在函数库中供编程时选用。在程序设计时,如果能够善于使用函数,则可以减少重复编写程序段的工作够善于使用函数,则可以减少重复编写程序段的工作量。量。一个简单的函数调用的例子:一个简单的函数调用的例子:#include#define N 10int scoreN=97,90,88,82,79,78,73,68,66,65;void function1()int i,s=0;for(i=1;iN;i+)s=s+scorei;printf(“平均分为:平均分为:%fn”,(float)s/N);return;int function2(int n)int i,j,k=-1;for(i=1;i=0)printf(“该分数在该分数在%d个分数个分数 中排名第中排名第%。”,N,t+1);else printf(“不存在此分数!不存在此分数!”);return 0;函数函数function1实现计算平均分;函数实现计算平均分;函数function2用来查找给定分数的位置,若给定分数在数组中用来查找给定分数的位置,若给定分数在数组中不存在,则返回值为不存在,则返回值为-1。在在C语言中,从函数定义的角度看,函数可分为如下两种:语言中,从函数定义的角度看,函数可分为如下两种:(1)标准函数,即库函数。是由)标准函数,即库函数。是由C编译系统提供的,用户编译系统提供的,用户不必自己定义、可以直接使用的函数。例如:不必自己定义、可以直接使用的函数。例如:printf、scanf、getchar、putchar等函数都是标准函数。等函数都是标准函数。附录附录D中给出了常用的库函数。中给出了常用的库函数。(2)用户自定义函数。是由用户自己编写的函数,以解决用户自定义函数。是由用户自己编写的函数,以解决用户的专门需要。用户的专门需要。例例7.1中的中的star和和square1函数是用户自定义函数。函数是用户自定义函数。7.2 函数的定义根据有无参数,可以将函数分为如下两种形式:根据有无参数,可以将函数分为如下两种形式:1无参函数无参函数定义形式如下:定义形式如下:类型标识符类型标识符 函数名(函数名()/*函数的首部函数的首部*/声明部分声明部分 /*函数体函数体*/执行部分执行部分 类型标识符用来说明函数返回值的类型,也称为函数的类类型标识符用来说明函数返回值的类型,也称为函数的类型。若省略类型标识符,默认返回值类型为整型;当函数型。若省略类型标识符,默认返回值类型为整型;当函数无返回值时,可以指定函数的类型为无返回值时,可以指定函数的类型为void。在例在例7.1中的中的function1函数为无参函数。函数为无参函数。2有参函数有参函数例例7.2 编写一个函数,编写一个函数,求两个数的最大值。求两个数的最大值。程序为:程序为:int max(int a,int b)int x;if(ab)x=a;else x=b;return x;上面定义了有参函数上面定义了有参函数max,参数为,参数为a和和b。return语语句用来返回句用来返回函数值。函数值。l定义形式如下:定义形式如下:l类型标识符类型标识符 函数名(形参表列)函数名(形参表列)l /*函数的首部函数的首部*/l l 声明部分声明部分 /*函数体函数体*/l 执行部分执行部分l l例例7.1中的中的function2函数为有参函数。函数为有参函数。l对函数定义的几点说明:对函数定义的几点说明:l(1)函数名的命名要符合标识符的命名规则,同一程序中)函数名的命名要符合标识符的命名规则,同一程序中函数不能重名,一个函数名用来唯一标识一个函数。函数不能重名,一个函数名用来唯一标识一个函数。l(2)无参函数的形参表是空的,但)无参函数的形参表是空的,但“()()”不能省略;有不能省略;有参函数,要说明每一个形参的类型,形参可以是变量名、参函数,要说明每一个形参的类型,形参可以是变量名、数组名、指针变量名等,形参表列中若多于一个形参,则数组名、指针变量名等,形参表列中若多于一个形参,则形参之间用逗号分隔。形参之间用逗号分隔。l(3)花括号内的部分称为)花括号内的部分称为“函数体函数体”。函数体由声明部分。函数体由声明部分和执行部分构成。声明部分对函数内所使用变量的类型和和执行部分构成。声明部分对函数内所使用变量的类型和被调用的函数进行定义和声明;执行部分是实现函数功能被调用的函数进行定义和声明;执行部分是实现函数功能的语句序列。的语句序列。l(4)当函数体为空时,称此函数为空函数。调用空函数时,)当函数体为空时,称此函数为空函数。调用空函数时,什么工作也不做。什么工作也不做。l(5)函数定义时,旧版的)函数定义时,旧版的C语言中,函数首部中的形参表语言中,函数首部中的形参表列仅包含形参,形参的类型另起一行来说明;新版的列仅包含形参,形参的类型另起一行来说明;新版的C语言语言中,函数首部中的形参表列包含形参的类型和形参。中,函数首部中的形参表列包含形参的类型和形参。l例如:例如:int max(int x,int y)为新版的函数定义方式,为新版的函数定义方式,l 而而 int max(x,y)l int x,y;l为旧版的函数定义方式。为旧版的函数定义方式。l一般来说,在新版的一般来说,在新版的C语言中以上两种定义方式都能使用。语言中以上两种定义方式都能使用。7.3 函数的参数和函数的返回值 7.3.1 形式参数和实际参数形式参数和实际参数l定义函数时的参数称为定义函数时的参数称为形式参数形式参数,简称为,简称为形参形参。形参在该函。形参在该函数数未被调用时是没有确定的取值未被调用时是没有确定的取值的,只是形式上的参数。调的,只是形式上的参数。调用函数时的参数称为用函数时的参数称为实际参数实际参数,简称为,简称为实参实参。实参可以是变实参可以是变量、常量或表达式,有确定的取值量、常量或表达式,有确定的取值,是实实在在的参数。函,是实实在在的参数。函数定义时形参不占内存,只有发生调用时,形参才被分配内数定义时形参不占内存,只有发生调用时,形参才被分配内存单元,接受实参传来的数据。存单元,接受实参传来的数据。l定义函数时必须定义形参的类型。定义函数时必须定义形参的类型。函数的形参与实参要求在函数的形参与实参要求在个数上相等,并且对应的形参和实参的类型要相同。个数上相等,并且对应的形参和实参的类型要相同。形参和形参和实参可以同名,形参是该函数内部的变量,即使形参和实参实参可以同名,形参是该函数内部的变量,即使形参和实参同名,也是两个不同的变量,占用不同的内存单元。同名,也是两个不同的变量,占用不同的内存单元。l例例7.3 数组中存储若干个数码数组中存储若干个数码(可以重复可以重复),编写一个函数,对于给定的一,编写一个函数,对于给定的一个数码,统计该数码在数组中出现的次数。主函数可以多次调用上面的个数码,统计该数码在数组中出现的次数。主函数可以多次调用上面的函数,实现多次统计输出。函数,实现多次统计输出。l#includelvoid fun(int b)/*函数定义,函数定义,b为形参为形参*/l int st20=2,6,3,5,7,1,4,3,4,2,2,6,6,1,7,5,5,2,1,7;l int k,n=0;l for(k=0;k20;k+)if(stk=b)n+;l printf(n%d appear%d times.n,b,n);llint main()l int a,yn=0;l while(yn=0)l printf(Input a number(09):);l scanf(%d,&a);fun(a);/*调用函数,调用函数,a为实参为实参*/l printf(If continue,please input 0,otherwise input 1:);l scanf(%d,&yn);l l return 0;l l例例7.3 数组中存储若干个数码数组中存储若干个数码(可以重复可以重复),编写一个函,编写一个函数,对于给定的一个数码,统计该数码在数组中出现的数,对于给定的一个数码,统计该数码在数组中出现的次数。主函数可以多次调用上面的函数,实现多次统计次数。主函数可以多次调用上面的函数,实现多次统计输出。输出。l运行程序,显示及输入输出可以如下:运行程序,显示及输入输出可以如下:lInput a number(09):3l3 appear 2 times.lIf continue,please input 0,otherwise input 1:0lInput a number(09):9l9 appear 0 times.lIf continue,please input 0,otherwise input 1:17.3.2 函数的返回值函数的返回值 l在执行被调用函数时,如果要将被调用函数的值在执行被调用函数时,如果要将被调用函数的值返回给调用它的函数,则需要使用返回给调用它的函数,则需要使用return语句。语句。return语句返回的数据,称为返回值。返回值的语句返回的数据,称为返回值。返回值的类型,由定义函数时的函数类型来决定。类型,由定义函数时的函数类型来决定。return语句的格式为:语句的格式为:l return 表达式;表达式;或或 return(表达式);(表达式);lreturn后面的表达式,即为函数的返回值,表达后面的表达式,即为函数的返回值,表达式可以是变量、常量或表达式。若不需要函数返式可以是变量、常量或表达式。若不需要函数返回任何数据时,可以指定函数的类型为回任何数据时,可以指定函数的类型为void。例例7.4 编写函数,求两个实数编写函数,求两个实数x、y的和,求的和,求x2和和y2的平均值。的平均值。include float fadd(float a,float b)/*函数定义函数定义*/float s;s=a+b;return(s);/*返回计算结果:两个实数的和返回计算结果:两个实数的和*/int main()float x,y,sum,aver;scanf(“%f,%f”,&x,&y);/*输入两个实数输入两个实数*/sum=fadd(x,y);/*函数调用函数调用*/aver=fadd(x*x,y*y)/2;printf(“n%f,%f”,sum,aver);return 0;例例75 求求3到到100之间的所有素数。调用函数判断一个数是否是素数,要求:之间的所有素数。调用函数判断一个数是否是素数,要求:若函数的返回值是若函数的返回值是1,表示该数是素数;若函数的返回值是,表示该数是素数;若函数的返回值是0,则表示该数不,则表示该数不是素数是素数。#include#include int prime(int i)/*函数定义函数定义*/int j,k,flag=1;k=sqrt(i);for(j=2;j=k;j+)if(i%j=0)flag=0;break;return flag;int main()int i;for(i=3;i100;i+)if(prime(i)=1)/*函数调用函数调用*/printf(%4d,i);printf(n);return 0;输出如下:输出如下:3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 7.4 函数的调用函数的调用7.4.1 函数调用的一般形式函数调用的一般形式函数调用的一般形式为:函数调用的一般形式为:函数名(实参表列);函数名(实参表列);如果是调用无参函数,则实参表列可以没有,但括如果是调用无参函数,则实参表列可以没有,但括弧不能省略。弧不能省略。如果实参表列包含多个实参,则各参数间用逗号隔如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应一致。实参开。实参与形参的个数应相等,类型应一致。实参与形参应按顺序一一对应,实参传递数据给形参。与形参应按顺序一一对应,实参传递数据给形参。7.4.2 函数调用的方式函数调用的方式l按函数在程序中出现的位置来划分,可以有以下三种按函数在程序中出现的位置来划分,可以有以下三种函数调用方式:函数调用方式:l1函数语句。函数语句。把函数调用作为一个语句,如例把函数调用作为一个语句,如例7.1中中的的function1()的调用,这时不要求函数带回值,只的调用,这时不要求函数带回值,只要求函数完成一定的操作。要求函数完成一定的操作。l2函数表达式。函数表达式。函数调用出现在一个表达式中,如函数调用出现在一个表达式中,如例例7.4中中aver=fadd(x*x,y*y)/2,这时要求函数带回一,这时要求函数带回一个确定的值参加表达式的运算。个确定的值参加表达式的运算。l3函数的参数。函数的参数。函数调用作为另一个函数的实参。函数调用作为另一个函数的实参。l函数调用作为另一个函数的参数,实质上也是函数表函数调用作为另一个函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是达式形式调用的一种,因为函数的参数本来就要求是表达式。表达式。l例例7.6 编程求编程求4个整数的最大值,要求调用个整数的最大值,要求调用“求两个整数最大值求两个整数最大值”的函数来完成。的函数来完成。l#include lint imax(int x,int y)/*函数定义函数定义*/lreturn(xy?x:y);lint main()l int n1,n2,n3,n4,d;lscanf(“%d,%d,%d,%d”,&n1,&n2,&n3,&n4);ld=imax(imax(n1,n2),imax(n3,n4);/*函数调用函数调用*/lprintf(“The max=%d”,d);lreturn 0;l7.4.3 函数调用的说明函数调用的说明l1函数调用的过程函数调用的过程l函数调用的过程是:函数调用的过程是:l(1)传递参数值。对有参函数进行调用时,)传递参数值。对有参函数进行调用时,计算各个实参表达式的值,为所有的形参分配计算各个实参表达式的值,为所有的形参分配内存单元,并按顺序把实参的值传递给相应的内存单元,并按顺序把实参的值传递给相应的形参。形参。l(2)进入函数的声明部分,为函数体内声明)进入函数的声明部分,为函数体内声明的局部变量分配内存单元。的局部变量分配内存单元。l(3)执行函数中的语句,实现函数的功能,)执行函数中的语句,实现函数的功能,当遇到当遇到return语句或最外层的语句或最外层的“”时,释放时,释放形参和本函数体内定义的局部变量所占的内存形参和本函数体内定义的局部变量所占的内存空间,返回到调用它的函数。空间,返回到调用它的函数。2函数调用需要具备的条件函数调用需要具备的条件l在一个函数中调用另一函数(即被调用函数)需要具备如下一在一个函数中调用另一函数(即被调用函数)需要具备如下一些条件:些条件:l(1)首先被调用函数必须是已经存在的函数(是库函数或用户)首先被调用函数必须是已经存在的函数(是库函数或用户自定义的函数)。自定义的函数)。l(2)如果调用库函数,一般还应该在文件开头用)如果调用库函数,一般还应该在文件开头用#include命命令将调用有关库函数时所需用到的信息包含到文件中来。令将调用有关库函数时所需用到的信息包含到文件中来。l(3)如果使用用户自己定义的函数,而且该函数与调用它的函)如果使用用户自己定义的函数,而且该函数与调用它的函数在同一个文件中,一般还应该在调用它的函数中或主函数之数在同一个文件中,一般还应该在调用它的函数中或主函数之前对被调用的函数进行声明。在前对被调用的函数进行声明。在C语言中,函数的声明称为函语言中,函数的声明称为函数原型数原型(function prototype),使用函数的原型是,使用函数的原型是ANSI C的一的一个重要特点,它的作用是利用它在程序的编译阶段对调用函数个重要特点,它的作用是利用它在程序的编译阶段对调用函数的合法性进行全面检查。的合法性进行全面检查。函数声明的一般形式为:函数声明的一般形式为:类型标识符类型标识符 被调用函数的函数名(参数类型被调用函数的函数名(参数类型1,参数类型,参数类型2,););类型标识符类型标识符 被调用函数的函数名(参数类型被调用函数的函数名(参数类型1 参数名参数名1,参数类型,参数类型2 参数名参数名2,););上面两种函数声明的形式均可,前一种为基本形式,为了便于阅读程序,声明函数时也上面两种函数声明的形式均可,前一种为基本形式,为了便于阅读程序,声明函数时也可以加上参数名,即后一种形式,但编译系统不检查参数名。可以加上参数名,即后一种形式,但编译系统不检查参数名。若被调用的函数的定义出现在调用它的函数之前或函数返回值为整型或字符型时,可以若被调用的函数的定义出现在调用它的函数之前或函数返回值为整型或字符型时,可以不必声明。例如,可以把例不必声明。例如,可以把例7.4的程序改写为:的程序改写为:include float fadd(float a,float b);/*函数声明函数声明*/int main()float x,y,sum,aver;scanf(“%f,%f”,&x,&y);sum=fadd(x,y);/*函数调用函数调用*/aver=fadd(x*x,y*y)/2;printf(“n%f%f”,sum,aver);return 0;float fadd(float a,float b)/*函数定义函数定义*/float s;s=a+b;return(s);7.5 函数的嵌套和递归调用函数的嵌套和递归调用 7.5.1 函数的嵌套调用函数的嵌套调用 其执行过程为:其执行过程为:首先从首先从main()函数开始执行程序,当遇到调用函数开始执行程序,当遇到调用f1函数语函数语句时,转去执行函数句时,转去执行函数f1;在执行函数;在执行函数f1的过程中,当遇到调用的过程中,当遇到调用f2函数语句时,函数语句时,转去执行函数转去执行函数f2;在执行函数;在执行函数f2的过程中,当遇到的过程中,当遇到return语句或该函数的最语句或该函数的最外层外层“”时,返回函数时,返回函数f1,从调用,从调用f2函数语句的下一条语句继续执行函数语句的下一条语句继续执行f1;在函数在函数f1里,当遇到里,当遇到return语句或该函数的外层语句或该函数的外层“”时,返回到时,返回到main函数,函数,从调用从调用f1函数语句的下一条语句继续执行;最后遇到函数语句的下一条语句继续执行;最后遇到main函数的外层函数的外层“”时,程序运行结束。时,程序运行结束。linclude ldouble sum(int m);l /*函数声明函数声明*/llong fact(int p);l /*函数声明函数声明*/lint main()ll int n;float s;l printf(“please input n:”);l scanf(“%d”,&n);l s=sum(n);/*函数调用函数调用*/l printf(“ne=%f”,s);l return 0;ldouble sum(int m)/*函数定义函数定义*/double sl=1;int i;for(i=1;i=m;i+)sl+=1.0/fact(i);/*函数调用函数调用*/return(sl);long fact(int p)/*函数定义函数定义*/long f=1;int i;for(i=1;i1时时“f(n)=n f(n-1)”给出的是递归公式,给出的是递归公式,n=1或或n=0时给出的时给出的“f(n)=1”是递归的终结条件。是递归的终结条件。l例例7.8 计算计算n!的递归程序。!的递归程序。l程序如下:程序如下:l#include llong fact(int n);/*函数声明函数声明*/lint main()ll int n;l printf(“nplease enter n:”);l scanf(“%d”,&n);l printf(“n n!=%ld”,fact(n);/*函数调用函数调用*/l return 0;lllong fact(int n)/*函数定义函数定义*/ll if(n=1|n=0)return(1);l /*若是终结条件,返回终结条件下的值若是终结条件,返回终结条件下的值*/l else return(n*fact(n-1);l /*若非终结条件,递归调用函数自身若非终结条件,递归调用函数自身*/l递归求解过程的两个阶段递归求解过程的两个阶段l调用调用l返回返回(1)调用过程:不断调用递归函数,直至最终达到递归终结条件。调用过程:不断调用递归函数,直至最终达到递归终结条件。(2)返回过程:由终结递归条件返回开始,沿调用过程的逆过程,逐一求返回过程:由终结递归条件返回开始,沿调用过程的逆过程,逐一求值返回,直至函数的最初调用结束。值返回,直至函数的最初调用结束。#include long fib(int n);/*函数声明函数声明*/int main()int i;for(i=1;i1););l(2)将)将1个盘从一个座移到另一个座上。个盘从一个座移到另一个座上。l可以编写两个函数分别实现上面的两类操作,用可以编写两个函数分别实现上面的两类操作,用hanoi函数实现第函数实现第1类操作,类操作,用用move函数实现第函数实现第2类操作。完整程序如下:类操作。完整程序如下:#include void move(char x,char y)printf(“%c-%cn”,x,y);void hanoi(int n,char one,char two,char three)if (n=1)move(one,three);else hanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three);main()int m;scanf(“%d”,&m);hanoi(m,A,B,C);7.6 数组作为函数的参数数组作为函数的参数l数组元素同单个变量一样,可以作为函数组元素同单个变量一样,可以作为函数的实参,其用法与一般变量相同,但数的实参,其用法与一般变量相同,但要求函数的相应形参与数组元素类型一要求函数的相应形参与数组元素类型一致。致。l数组名既可以作为函数的实参也可以作数组名既可以作为函数的实参也可以作为函数的形参。当用数组名作为函数的为函数的形参。当用数组名作为函数的参数时,函数的实参与形参都应该用数参数时,函数的实参与形参都应该用数组名,且实参数组与形参数组的类型必组名,且实参数组与形参数组的类型必须严格一致。须严格一致。l例7.10 编写程序,将一维数组中的每个元素的值加编写程序,将一维数组中的每个元素的值加3,并显示出来。,并显示出来。l#include lvoid add(int b,int n);/*函数声明函数声明*/lint main()l int a=0,1,2,3,4,5,6,7,8,9;l int i;l add(a,10);/*函数调用函数调用*/l for(i=0;i10;i+)l printf(“%3d”,ai);l return 0;llvoid add(int b,int n)/*函数定义函数定义*/l int i;l for(i=0;in;i+)l bi+=3;l例例7.10程序说明:程序说明:1用数组名作函数参数,要求实参数组与形参数组类型应一致,用数组名作函数参数,要求实参数组与形参数组类型应一致,如不一致,结果将出错。如如不一致,结果将出错。如a、b类型都为整型数组。类型都为整型数组。l2形参数组可以不指定大小,在定义数组时在数组名后面跟一个形参数组可以不指定大小,在定义数组时在数组名后面跟一个空的方括号即可。如形参数组空的方括号即可。如形参数组b未指定大小。未指定大小。l3.数组名作函数参数时,是把实参数组的起始地址传给形参数组,数组名作函数参数时,是把实参数组的起始地址传给形参数组,这样两个数组就共同占用一段存储单元。这样两个数组就共同占用一段存储单元。由于两个数组起始地址相同,占用同一段内存单元,所以,由于两个数组起始地址相同,占用同一段内存单元,所以,当形参数组中各元素值发生变化时,实参数组元素的值也发生相当形参数组中各元素值发生变化时,实参数组元素的值也发生相同的变化。同的变化。#include#define N 10float average(float a,int n);/*函数声明函数声明*/int main()float scoreN,aver;int i,num=0;printf(“input scores:n”);for(i=0;iN;i+)scanf(“%f”,&scorei);printf(“n”);aver=average(score,N);/*函数调用函数调用*/printf(“average=%fn”,aver);for(i=0;iN;i+)if(scoreiaver)num+;printf(“less than average:%d”,num);return 0;float average(float a,int n)/*函数定义函数定义*/int i;float aver,sum=a0;for(i=1;in;i+)sum=sum+ai;aver=sum/n;return(aver);程序运行结果如下:程序运行结果如下:input scores:100 56 78 98.5 87 99 67.5 75 97 77 average=83.500000less than average:5例例7.12 输入输入N个学生的成绩存入一维数组中,统计低于平均成绩的学生人数。个学生的成绩存入一维数组中,统计低于平均成绩的学生人数。7.7 局部变量和全局变量局部变量和全局变量 变量是程序运行过程中其值可以改变的量。编译系统变量是程序运行过程中其值可以改变的量。编译系统为变量分配内存单元,用来存放程序运行过程中的输入数为变量分配内存单元,用来存放程序运行过程中的输入数据、中间结果和最终结果等。每个变量都需要定义它的数据、中间结果和最终结果等。每个变量都需要定义它的数据类型,数据类型用来说明变量在内存中所占的字节数,据类型,数据类型用来说明变量在内存中所占的字节数,以及变量的运算规则。以及变量的运算规则。每个变量都有其属性,每个变量都有其属性,变量的属性包含两个方面的内变量的属性包含两个方面的内容,即变量的作用域和变量的存储类别。容,即变量的作用域和变量的存储类别。变量的变量的作用域是指变量的合法使用范围作用域是指变量的合法使用范围,变量只能在,变量只能在它的作用域内被使用。它的作用域内被使用。变量的存储类别是指变量在内存中的存储位置变量的存储类别是指变量在内存中的存储位置,变量,变量的存储类别决定着变量的生存期,变量的生存期是变量在的存储类别决定着变量的生存期,变量的生存期是变量在内存或寄存器中存在的时间段。内存或寄存器中存在的时间段。变量从作用域来区分可分为局部变量和全局变量。变量从作用域来区分可分为局部变量和全局变量。7.7.1 局部变量局部变量l 局部变量的局部变量的概念:概念:在一个函数内部定义的变量是内部在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,称为局部变量变量,它只在本函数范围内有效,称为局部变量l 局部变量的局部变量的作用域:作用域:局部变量的作用域是定义该变量局部变量的作用域是定义该变量的函数或复合语句的内部,在它的作用域之外,局部变量的函数或复合语句的内部,在它的作用域之外,局部变量是不可见的,换言之,在函数或复合语句内定义的局部变是不可见的,换言之,在函数或复合语句内定义的局部变量是不能被其它的函数或复合语句所引用的。量是不能被其它的函数或复合语句所引用的。l 局部变量的生存期局部变量的生存期:是从该变量被定义到函数的结束或是从该变量被定义到函数的结束或复合语句的结束这段时间。复合语句的结束这段时间。l 局局部部变变量量包包含含有有自自动动类类型型变变量量、寄寄存存器器类类型型变变量量和和内内部部静静态态类类别别变变量量。另另外外,函函数数的的形形参参也也属属于于局局部部变变量量,因因为函数形参的作用范围只在该函数体内。为函数形参的作用范围只在该函数体内。l 使使用用局局部部变变量量有有助助于于实实现现信信息息隐隐蔽蔽,即即使使不不同同的的函函数数定义了同名的局部变量,也不会互相影响。定义了同名的局部变量,也不会互相影响。局部变量的例子局部变量的例子floatfloat f1 f1(int (int a a)int int b b,c c;charchar f2 f2(int(int x x,int,int y y)int int i i,j j;mainmain()()int int m m,n n;a,b,c的作用域x,y,i,j的作用域m,n的作用域复合语句内部的局部变量复合语句内部的局部变量main()int a,b;int c;c=a+b;c的作用域a,b的作用域全局变量全局变量l 全局变量概念:全局变量概念:在函数外任意位置定义的变量称为外部变在函数外任意位置定义的变量称为外部变量,也称为全局变量。量,也称为全局变量。l 全局变量作用域:全局变量作用域:从定义它的位置开始,直至它所在源程从定义它的位置开始,直至它所在源程序文件结束。若是不在作用范围的段内,想使用该全局变量,序文件结束。若是不在作用范围的段内,想使用该全局变量,可以在段内利用声明的方式拓展变量的作用范围。可以在段内利用声明的方式拓展变量的作用范围。l l 全全局局变变量量的的使使用用增增加加了了函函数数之之间间传传递递数数据据的的途途径径,在在全全局局变变量量作作用用域域内内的的任任何何函函数数都都能能引引用用该该全全局局变变量量,一一个个函函数数对对全全局局变变量量的的修修改改,能能影影响响到到其其它它引引用用这这个个变变量量的的函函数数,因因此此对对全全局局变变量量的的使使用用不不当当,会会产产生生意外的错误。意外的错误。l 全全局局变变量量的的使使用用会会使使得得函函数数的的通通用用性性降降低低,从从结结构构化化程程序序设设计计的的角角度度看看,函函数数应应是是完完成成单单一一功功能能的的程程序序段段,过过多多使使用用全全局局变变量量,会会使使函函数数之之间间的的依依赖赖性性增增加加,增增强强函函数数的的耦耦合合性性。一一般般情情况况下下,除除非非性性能能的的特特别别要求,建议避免使用全局变量。要求,建议避免使用全局变量。l 全局变量与局部变量同名时,在局部变量的作用域内,该全局变量与局部变量同名时,在局部变量的作用域内,该局部变量有效,同名的全局变量被屏蔽。局部变量有效,同名的全局变量被屏蔽。全局变量的例子全局变量的例子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的作用域l例例7.13 分析下列程序的运行结果。分析下列程序的运行结果。l#include lint a=0;float b;/*定义全局变量定义全局变量a,b*/lfloat func(int s,int n);/*函数声明函数声明*/lint main()l int k;int x10;/*定义局部变量定义局部变量*/l for(k=0;k10;k+)l scanf(“%d”,&xk);l b=func(x,10);l for(k=0;kb)a+;l printf(“n%d”,a);/*输出全局变量输出全局变量a的值的值*/l return 0;llfloat func(int s,int n)lint k,a=0;float b;/*定义局部变量定义局部变量k,a,b*/l for(k=0;kn;k+)a=a+sk;l printf(“n%d”,a);/*输出局部变量输出局部变量a的值的值*/l b=(float)a/n;l return(b);l 7.8 变量的存储类别变量的存储类别l 把变量分为全局变量和局部变量是从变量的作用域的角度对把变量分为全局变量和局部变量是从变量的作用域的角度对变量进行划分的。变量进行划分的。l 也可以从变量值存在的时间(即生存期)的角度来划分变量,也可以从变量值存在的时间(即生存期)的角度来划分变量,可以把变量分为静态存储变量和动态存储变量两种。可以把变量分为静态存储变量和动态存储变量两种。l 所谓静态存储变量是指在程序运行期间分配固定的存储空所谓静态存储变量是指在程序运行期间分配固定的存储空间的变量;而动态存储变量是在程序运行期间根据需要进行动态间的变量;而动态存储变量是在程序运行期间根据需要进行动态的分配存储空间的变量。的分配存储空间的变量。l C程序运行时占用的内存空间分为三部分,即程序区、静态程序运行时占用的内存空间分为三部分,即程序区、静态存储区和动态存储区三部分