第六章函数(时间:5次课,10学时)第六章函数学习目的与要求:一个实用的C语言源程序总是由许多函数组成,这些都是根据实际任务,由用户自己来编写的。在这些函数中可以调用C提供的库函数,也可以调用由用户自己或他人编写的函数。但是,一个C语言源程序无论包含了多少函数,C程序总是从main函数开始执行。本章将讨论如何调用C提供的库函数;如何自己来定义并调用函数;如何使用函数中的各种变量,以及内部函数和外部函数的区别。第六章函数6.1概述6.2函数定义的一般形式6.3C语言中函数的类型6.4函数的调用6.5函数的说明6.6函数的嵌套调用6.7函数的递归调用6.8C语言中的变量6.9内部函数和外部函数6.10上机实训概述在C语言中,函数是程序的基本组成单位,因此可以很方便地用函数作为程序模块来实现C语言程序的编写。利用函数,不仅可以实现程序的模块化,使程序设计变得简单和直观,提高了程序的易读性和可维护性,而且还可以把程序中普通用到的一些计算或操作编成通用的函数,以供随时调用,这样可以大大减轻程序员的代码工作量。C语言中的函数相当于其它高级语言的子程序。通过对函数模块的调用实现特定的功能。函数定义的一般形式函数定义的一般形式分为两种,一种是无参函数的定义,另一种是有参函数的定义,无参函数是指在函数定义、函数说明及函数调用时均不带参数。1.无参函数的一般形式类型说明符函数名(){类型说明语句}函数定义的一般形式其中类型说明符和函数名称为函数头。类型说明符指明了本函数的类型,函数的类型实际上是函数返回值的类型,该类型说明符与第二章介绍的各种类型说明符相同。函数名是由用户定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。{}中的内容称为函数体。在函数体中也有类型说明,这是对函数体内部所用到的变量的类型说明。在很多情况下都不要求无参函数有返回值,此时函数类型符可以写为void。函数定义的一般形式例6.1voidHello(){printf(“HELLO,MYFRIEND\n”);}Hello函数是一个无参函数,当被其它函数调用时,输出HELLO,MYFRIEND字符串。函数定义的一般形式2.有参函数的一般形式类型说明符函数名(形式参数表)形式参数类型说明{类型说明语句}有参函数比无参函数多了两个内容,其一是形式参数表,其二是形式参数类型说明。在形式参数表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。形参既然是变量,当然必须给以类型说明。例如,定义一个函数,用于求两个数中的大数,可写为:函数定义的一般形式例6.2intmax(a,b)inta,b;{if(ab)returna;elsereturnb;}第一行说明max函数是一个整型函数,其返回的函数值是一个整数。形参为a,b。第二行说明a,b均为整型量。a,b的具体值是由主调函数在调用时传送过来的。在{}中的函数体内,除形参外没有使用其它变量,因此只有语句而没有变量类型说明。上边这种定义方法称为“传统格式”。这种格式不易于编译系统检查,从而会引起一些非常细微而且难于跟踪的错误。ANSIC的新标准中把对形参的类型说明合并到形参表中,称为“现代格式”。函数定义的一般形式max函数用现代格式定义如下:例6.3intmax(inta,intb){if(ab)returna;elsereturnb;}现代格式在函数定义和函数说明(后面将要介绍)时,给出了形式参数及其类型,在编译时易于对它们进行查错,从而保证了函数说明和定义的一致性。在max函数体中的return语句是把a(或b)的值作为函数的值返回给主调函数。有返回值的函数中至少应有一个return语句。在C程序中,一个函数的定义可以放在任意位置,既可放在主函数main之前,也可放在main之后。函数的参数1.函数的参数函数的参数分为形参和实参两种。形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。发生函数调用时,主调函数把实参的值传送给被调函数的形参,从而实现主调函数向被调函数的数据传送。因此可以说形参和实参的功能是进行数据传送。函数的参数2.函数的形参和实参具有以下特点:(1)形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。(2)实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。(3)实参和形参在数量上,类型上,顺序上应严格一致,否则会发生“类型不匹配”的错误。(4)函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。例6.4可以说明这个问题。函数的参数例6.4voidmain(){intn;n=5;s(n);printf(“n=%d\n”,n);}ints(intn){n=n+1;printf(“n=%d\n”,n);}函数的参数本程序中main函数为主调函数,s函数为被调函数。主函数把n的值5作为实参,在调用时传送给s函数的形参n(注意,本例的形参变量和实参变量的标识符都为n,但这是两个不同的量,各自的作用域不同)。在主函数中用printf语句输出一次n值,这个n值是实参n的值,即5。在函数s中也用printf语句输出了一次n值,这个n值是形参最后取得的n值,即6。从运行情况可见,实参的值不随形参的变化而变化。一般情况下,为了避免混淆,在编程时使用的实参变量名和形参变量名不要相同。如上面的被调函数可以写成如下的形式:ints(intt){t=t+1;printf(“t=%d\n”,t);}函数的返回值函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。如调用正弦函数取得正弦值,调用例6.3的max函数取得的最大数等。对函数的返回值(或称函数的值)有以下一些说明:(1)函数的值只能通过return语句返回主调函数。return语句的一般形式为:return表达式;或者为:return(表达式);该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个return语句,但每次调用只能有一个return语句被执行,因此只能返回一个函数值。(2)函数返回值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类型为准,自动进行类型转换。(3)如函数值为整型,在函数定义时可以省去类型说明。(4)不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。函数的返回值例6.4中函数s并不向主函数返回函数值,因此可定义为:voids(intn){……}一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。例如,在定义s为空类型后,在主函数中写下述语句sum=s(n);就是错误的。为了使程序有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型。语言中函数的类型1.从函数定义的角度看2.C语言的函数兼有其它语言中的函数和过程两种功能,从这个角度看3.从主调函数和被调函数之间数据传送的角度看有返回值函数无返回值函数无参函数有参函数库函数用户定义函数函数的调用在程序中是通过对函数的调用来执行函数体的,其过程与其它语言的子程序调用相似。C语言中,函数调用的一般形式为:函数名(实际参数表)对无参函数调用时则无实际参数表,但()号不可省略。实际参数表中的参数可以是常数,变量或其它构造类型数据及表达式,各实参之间用逗号分隔。实参与形参的个数应相等,类型应一致。实参与形参按顺序对应,一一传递数据。可以用以下几种方式调用函数:1.函数语句例如:printf(“%d”,a);scanf(“%d”,&b);2.函数表达式例如:z=max(x,y);3.函数实参例如:printf(%d,max(x,y));函数的说明在主调函数中调用某函数之前应对该被调函数进行说明,这与使用变量之前要先进行变量说明是一样的。在主调函数中对被调函数作说明的目的是使编译系统知道被调函数返回值的类型,以便在主调函数中按此类型对返回值作相应的处理。对被调函数说明的一般格式为:类型说明符被调函数名();如例6.6就包含这样的“说明”函数的说明例6.6Main(){floatadd();/*函数说明*/floata,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);/*函数调用*/printf(“sumis%f”,c);}floatadd(floatx,y)/*函数定义*/{floatz;Z=x+y;Return(z);}函数的说明C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。1.如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。例6.4的主函数中未对函数s作说明而直接调用即属此种情形。2.当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数作说明而直接调用。函数的说明例6.7intmax(inta,intb){if(ab)returna;elsereturnb;}main(){intx,y;scanf(“%d,%d”,&x,&y);printf(“max=%d\n”,max(x,y));}3.如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。函数的说明例6.8charstr();floatf();main(){……}charstr(inta){……}floatf(floatb){……}其中第一,二行对str函数和f函数预先作了说明。因此在以后各函数中无须对str和f函数再作说明就可直接调用。注