C语言程序设计课件:函数_第1页
C语言程序设计课件:函数_第2页
C语言程序设计课件:函数_第3页
C语言程序设计课件:函数_第4页
C语言程序设计课件:函数_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言程序设计

函数8.1函数定义

8.2函数参数和返回值

8.2.1形式参数和实际参数

8.2.2函数返回值

8.3函数调用

8.3.1调用方式

8.3.2函数说明

8.3.3函数嵌套调用

8.3.4函数递归调用

8.4数组作为函数参数

8.5局部变量和全局变量

8.5.1局部变量

8.5.2全局变量

8.6存储类型

8.6.1auto存储类型

8.6.2extern存储类型

8.6.3register存储类型

8.6.4static存储类型8.7内部函数和外部函数

C语言不仅提供了极为丰富的库函数(如TurboC,MSC都提供了三百多个库函数),还允许用户建立自己定义的函数。用户编写一个个相对独立的函数模块算法,然后用调用的方法来使用函数。例8-1带参函数程序main(){inta,b,c;scanf(“%d,%d”,&a,&b);c=fun(a,b);printf(“funis%d”,c);}fun(intx,inty){intz;if(x>y)z=x;elsez=y;return(z);}说明:(1)一个源程序文件由一个或多个函数组成。一个源程序文件是一个编译单位,即以源文件为单位进行编译,而不是以函数为单位进行编译。(2)一个C语言程序由一个或多个源程序文件组成。对于较大的程序,一般不希望全放在一个文件中,而是将函数和其他内容(如预编译命令)分别放到若干个源文件中,再由若干个源文件组成一个C语言程序。这样可以分别编写、分别编译,提高调试效率。一个源文件可以为多个C语言程序共用。(3)C语言程序的执行从main函数开始,调用其它函数后流程回到main函数,在main函数中结束整个程序的运行。(4)所有函数都是平行的,即在定义函数时是相互独立的,一个函数并不从属于另一个函数,即函数不能嵌套定义,但可以相互调用,甚至嵌套调用、递归调用(不能调用main函数)。

(5)从用户使用角度看,函数有两种。●标准函数,即库函数。这是由系统提供的,用户无须定义,也不必在程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。●用户自己定义的函数,以解决用户的专门需要。(6)从函数的形式看,函数分两类。●无参函数。在调用无参函数时,主调函数并不将数据传送给被调用函数,一般用来执行指定的一组操作。无参函数可以带回也可以不带回函数值,但一般以不带回函数值居多。●有参函数。在调用函数时,在主调函数和被调函数之间有参数传递,也就是说,主调函数可以将数据传给被调函数使用,被调用函数中的数据也可以带回来供主调函数使用。8.1函数的定义1.函数的定义(1)无参函数的一般形式类型说明符函数名(){类型说明;语句;}(2)有参函数的一般形式

类型说明符函数名(形式参数表){类型说明;

语句;}voidHello(){printf("Hello,world\n");}intmax(a,b)inta,b;{if(a>b)returna;elsereturnb;}8.2.1形式参数和实际参数

函数的形参和实参具有以下特点:1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元,因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。3.实参和形参在数量上、类型上、顺序上应严格一致,否则会发生“类型不匹配”的错误。4.函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参,因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。8.2函数参数和返回值

例8-3求两整数中的较大值。#include<stdio.h>intmax(inta,intb);voidmain(){ inta,bmax; printf("输入两整数:"); scanf("%d%d",&a,&b); max=max(a,b);/*调用max函数,在表达式中出现*/ printf("\n两整数中的较大值是%d\n",max);}intmax(inta,intb)/*求两整数中的较大值函数定义*/{ if(a>b)returna; elsereturnb;}函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值,这就是函数的返回值。说明:(1)函数的值只能通过return语句返回主调函数。return语句的一般形式为:

return表达式;

return(表达式);return;该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个return语句,但每次调用只能有一个return语句被执行,因此只能返回一个函数值。8.2.2函数返回值

(2)函数值得类型。既然函数可以有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。例如:intmax(inti,inty)charletter(charc1,charc2)floatf(floatx)doublemin(doublex,doubley)C语言还规定,凡不加类型声明的函数,一律自动按整型处理。(3)函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类型为准,自动进行类型转换。(4)不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。voids(intn){…}一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。例如,在定义s为空类型后,在主函数中写下述语句sum=s(n);就是错误的。为了使程序有良好的可读性并减少出错,不要求返回值的函数都应定义为空类型。函数调用的一般形式为

被调用函数名([参数表达式1,参数表达式2,…,参数表达式n]);其中,参数前不加数据类型说明,参数表达式可以是常量、变量或表达式。各个参数表达式之间用逗号分割。参数表示式的个数与该函数定义时形式参数的个数、数据类型都应该匹配,否则会出现预料不到的结果。如果被调用函数是无参函数,即[]中没有内容时,函数名后面的括号不要省略。使用C语言的库函数就是函数简单调用的方法。例如:

main()

{

printf(“******\n”);

}8.3函数调用

8.3.1调用方式

(1)函数表达式

函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数有返回值。例如:

z=max(x,y)*8;其中,函数max是赋值表达式的一部分,它的值乘以8后在赋予变量z(2)函数语句函数调用的一般形式加上分号即构成函数语句。例如:

printf(“%d”,m);

max(x,y);等都是以函数语句的方式调用函数。(3)函数实参函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参传递给调用函数,因此要求该函数必须有返回值。例如:

printf(“%d”,max(m,n));上述语句是把max函数的返回值又作为printf函数的实参来使用。对被调函数的说明也有两种格式,一种为传统格式。其格式为:类型说明符被调函数名();这种格式只给出函数返回值的类型,被调函数名及一个空括号。这种格式由于在括号中没有任何参数信息,因此不便于编译系统进行错误检查,容易发生错误。另一种为现代格式,其一般形式为:类型说明符被调函数名(类型形参,类型形参…);

或为:类型说明符被调函数名(类型,类型…);

现代格式的括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以防止可能出现的错误。max函数的说明若用传统格式可写为:intmax();用现代格式可写为:intmax(inta,intb);或写为:intmax(int,int);8.3.2函数说明

注意:(1)被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)(2)在调用系统函数时,需要用包含命令#include“头文件名.h”将定义系统函数的库文件包含在本程序中,有关包含命令的相关知识在后面章节中详细介绍。(3)如果调用函数和主函数在一个编译单元中,则在书写顺序上被调用函数比主函数先出现;或者被调用函数虽然在主函数之后出现,而被调用函数的数据类型是整型或字符型,可以不对被调函数加以说明,除了上述两种情况以外,都要对被调用函数加以说明。函数的原型说明8.3.3函数嵌套调用

例8-5用以下近似公式编程计算ex的值,ex=1+x+x2/2!+x3/3!+…(前20项的和)。#include<stdio.h>floatf2(intn) {if(n==1)return1;elsereturn(f2(n-1)*n);}floatf1(intx,intn){inti;floatj=1;for(i=1;i<=n;i++)j=j*x;returnj;}voidmain(){floatexp=1.0;intn,x;printf(“Inputanumber:”);scanf(“%d”,&x);printf(“%\n”,x);exp=exp+x;for(n=2;n<=19;n++)exp=exp+f1(x,n)/f2(n);printf(“\nTheisexp(%d)=%8.4f\n”,x,exp);}一个函数在它的函数体内调用它自身称为递归调用。这种特殊的函数称为递归函数。递归调用有两种:直接递归调用和间接递归调用。8.3.4函数递归调用

例8-6用递归法计算n!。#include<stdio.h>longff(intn){longf;if(n<0)printf("n<0,inputerror");elseif(n==0||n==1)f=1;elsef=ff(n-1)*n;return(f);}voidmain(){intn;longy;printf("\ninputainteagernumber:\n");scanf("%d",&n);y=ff(n);printf("%d!=%ld",n,y);}例8-7Hanoi塔问题。一块板上有三根针,A,B,C。A针上套有64个大小不等的圆盘,大的在下,小的在上。要把这64个圆盘从A针移动C针上,每次只能移动一个圆盘,移动可以借助B针进行。但在任何时候,任何针上的圆盘都必须保持大盘在下,小盘在上。求移动的步骤:#include<stdio.h>move(intn,intx,inty,intz){if(n==1)printf("%c-->%c\n",x,z);else{move(n-1,x,z,y);printf("%c-->%c\n",x,z);move(n-1,y,x,z);}}voidmain(){inth;printf("\ninputnumber:\n");scanf("%d",&h);printf("thesteptomoving%2ddiskes:\n",h);move(h,'a','b','c');}

数组名能作为函数的形参,但不能作为函数的返回值类型。数组名作为实参时是传递数组首地址。形参数组实质是一个指针变量,占2字节,存实参数组的首地址。传址(传地址值)是C函数参数传递的第二种方法,效率高,用途广;但难度比传值(传数据值)大。8.4数组作为函数参数

2.数组名作为函数参数例8-8一维数组的数组元素值减2。#include<stdio.h>#defineN5 voidadd1(intx[],intn);voidmain(){inta[N]={6,7,8,9,10},i;printf("数组A[%d]:\n",N);for(i=0;i<N;i++)printf("a[%d]:%x%5d\n",i,&a[i],a[i]);add1(a,N);printf("\n数组A[%d:\n",N);for(i=0;i<N;i++)printf("a[%d]:%x%5d\n",i,&a[i],a[i]);}voidadd1(intx[],intn) {inti;printf("x中的值(地址):%x\n",x);printf("数组x[%d]:\n",n);for(i=0;i<n;i++)printf("x[%d]:%x%5d\n",i,&x[i],x[i]);for(i=0;i<n;i++) x[i]=x[i]-2;}例8-9有一个一维数组score,内放10个学生成绩,求平均成绩。#include<stdio.h>floataverage(floatarray[10]);voidmain(){floatscore[10],aver;inti;printf(“input10scores:\n”);for(i=0;i<10;i++)scanf(“%f”,&score[i]);printf(“\n”);aver=average(score);printf(“averagescoreis%5.2f”,aver);}floataverage(floatarray[10]){inti;floataver,sum=array[0];for(i=1;i<10;i++)sum=sum+array[i];aver=sum/10;return(aver);}局部变量也称为内部变量。局部变量是在函数内作定义说明的。它只在该函数范围内有效。也就是说,只有在包含变量说明的函数内部,才能使用被说明的变量,在此函数之外就不能使用这些变量了,离开该函数后再使用这种变量是非法的。例如:intf1(inta)/*函数f1*/{intb,c;……}a、b、c作用域。intf2(intx)/*函数f2*/{inty,z;}x、y、z作用域。voidmain(){intm,n;}m、n作用域。8.5局部变量和全局变量

8.5.1局部变量

关于局部变量的作用域还要说明以下几点:(1)主函数main()中定义的变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。(2)形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量。(3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。(4)在复合语句中也可定义变量,其作用域只在复合语句范围内。第8章函数8.5局部变量和全局变量例8-10定义变量的作用域。inta,b;/*外部变量*/voidf1()/*函数f1*/{……}floatx,y;/*外部变量*/intfz()/*函数fz*/{……}voidmain()/*主函数*/{……}/*全局变量x、y作用域,全局变量a、b作用域*/8.5.2全局变量

例8-11有一个一维数组,内放10个学生成绩,写一个函数,求出平均分,最高分和最低分。#include<stdio.h>floatMax,Min;floataverage(floatarray[],intn){inti;floataver,sum=array[0];Max=Min=array[0];for(i=1;i<n;i++){if(array[i]>Max)Max=array[i];elseif(array[i]<Min)Min=array[i];sum=sum+array[i];}aver=sum/n;return(aver);}voidmain(){floatave,score[10];inti;for(i=0;i<10;i++)scanf("%f",&score[i]);ave=average(score,10);printf("max=%6.2f\nmin=%6.2f\naverage=%6.2f\n",Max,Min,ave);}对于全局变量还有以下几点说明:

(1)外部变量可加强函数模块之间的数据联系,但降低这些函数的独立性。

(2)在同一源文件中,允许外部变量和内部变量同名。在内部变量的作用域内,外部变量将被屏蔽而不起作用。

(3)外部变量的作用域是从定义点到本文件结束。如果定义点之前的函数需要引用这些外部变量时,需要在函数内对被引用的外部变量进行说明。外部变量说明的一般形式为:extern数据类型

外部变量[,外部变量2……];注意:外部变量的定义和外部变量的说明是两回事。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在要使用该外部变量的函数内,而且可以出现多次。

#include<stdio.h>voidtestauto();voidmain(){inti;for(i=0;i<4;i++)testauto();printf("\n");}/*测试自动类局部变量的特性*/voidtestauto(){autointva=0;/*或intva=0;*/printf("%d”,va);va++;/*值不保留*/}自动变量的类型说明符为auto。这种存储类型是C语言程序中使用最广泛的一种类型。C语言规定,函数内凡未加存储类型说明的变量均视为自动变量。例8-12测试自动类型局部变量的特性。8.6.1auto存储类型

8.6存储类型

自动变量具有以下特点:(1)自动变量的作用域仅限于定义该变量的区域内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。

例如:intkv(inta){autointx,y;{autocharc;}/*c的作用域*/……}/*a、x、y的作用域*/(2)自动变量属于动态存储方式,只有在定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。在复合语句中定义的自动变量,在退出复合语句后也不能再使用,否则将引起错误。例8-13变量的作用域----自动变量。voidmain(){autointa,s=1,p=2; printf("\ninputanumber:\n");scanf("%d",&a);if(a>0){autos,p;s=a+a;p=a*a;}printf("s=%dp=%d\n",s,p);}(3)由于自动变量的作用域和生存期都局限于定义它的个体内(函数或复合语句内),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。外部变量的几个特点:(1)外部变量和全局变量是对同一类变量的两种不同角度的提法。全局变量是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。(2)当一个源程序由若干个源文件组成时,在一个源文件中定义的外部变量在其它的源文件中也有效。例如F1.C:inta,b;/*外部变量定义*/charc;/*外部变量定义*/voidmain(){……}F2.C:externinta,b;/*外部变量说明*/externcharc;/*外部变量说明*/func(intx,y){……}8.6.2extern存储类型

寄存器变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,这样可提高效率。变量的作用域----寄存器变量。#include<stdio.h>voidmain(){registerk,sum=0;for(k=1;k<=1000;k++)sum=sum+k;printf("sum=%d\n",sum);}8.6.3register存储类型

1.静态局部变量在局部变量的说明前再加上static说明符就构成静态局部变量。例如:staticinta,b;staticfloatarray[5]={1,2,3,4,5};静态局部变量属于静态存储方式,它具有以下特点:(1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。(2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。(3)允许对构造类静态局部量赋初值。(4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。8.6.4static存储类型静态变量的作用域。#include<stdio.h>voidmain(){inti;voidf();/*函数说明*/for(i=1;i<=10;i++)f();/*函数调用*/}voidf()/*函数定义*/{staticintj=0;++j;printf("%d\n",j);}2.静态全局变量在函数外部定义变量时,用static修饰的变量是静态类全局变量。它分配在数据区,作用范围也是从定义点开始到该文件结束,或称为文件作用域;但只限于该源文件,不能被其它源文件引用。静态类全局变量在执行main之前初始化;未初始化,其值为0。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论