《《c语言程序设计基础》5函数.ppt》由会员分享,可在线阅读,更多相关《《c语言程序设计基础》5函数.ppt(101页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第5章章 函数函数2第第5章章 函数函数本章内容本章内容 5.2 函数原型与函数调用函数原型与函数调用 5.3 函数的嵌套调用函数的嵌套调用 5.4 函数的递归调用函数的递归调用 5.1 函数基础知识函数基础知识3第第5章章 函数函数本章内容本章内容 5.6 变量的作用域变量的作用域5.7 变量的存储类别变量的存储类别 5.5 调用与被调用函数间的数据传递调用与被调用函数间的数据传递4 5.1 5.1 函数基础知识函数基础知识本节内容本节内容 5.1.2 函数的分类函数的分类 5.1.3 函数的定义函数的定义 5.1.1 函数的概念函数的概念55.1 5.1 函数基础知识函数基础知识v由图可
2、以看出一个由图可以看出一个C C语言程序可以包含若干个源文语言程序可以包含若干个源文件,而每个源文件又是由若干个函数构成的,因件,而每个源文件又是由若干个函数构成的,因此,也可以说函数是语言源程序的基本模块,此,也可以说函数是语言源程序的基本模块,程序的功能是通过对函数模块的调用来实现的。程序的功能是通过对函数模块的调用来实现的。C程序程序源程序文件源程序文件1函数函数1函数函数n源程序文件源程序文件n函数函数1函数函数m65.1.1 5.1.1 函数的概念函数的概念v函数,就是一个能够完成一定功能的执行代码段函数,就是一个能够完成一定功能的执行代码段。vC C语言程序的所有功能都是通过函数之
3、间的调用来语言程序的所有功能都是通过函数之间的调用来实现的。使用函数有以下优点:实现的。使用函数有以下优点:程序结构清晰,可读性好。程序结构清晰,可读性好。减少重复编码的工作量。减少重复编码的工作量。可多人共同编制一个大程序,缩短程序设计周期,提可多人共同编制一个大程序,缩短程序设计周期,提高程序设计和调试的效率。高程序设计和调试的效率。v可以将一些重复使用的功能或操作定义成一个函可以将一些重复使用的功能或操作定义成一个函数,在其他函数中如果需要可以直接调用这个函数,在其他函数中如果需要可以直接调用这个函数,而省掉了很多重复性的工作。并且使程序结数,而省掉了很多重复性的工作。并且使程序结构看起
4、来更加简单清晰。构看起来更加简单清晰。75.1.1 5.1.1 函数的概念函数的概念#include /包含预处理命令main()/主函数int max1(int x,int y);/max1函数声明int a,b,c;/声明部分,定义变量printf(Please input two integers:n);/调用printf函数 scanf(%d,%d,&a,&b);/调用scanf函数 c=max1(a,b);/调用max1函数printf(max=%dn,c);/调用printf函数 int max1(int x,int y)/定义max1函数 int z;if(xy)z=x;else
5、 z=y;return(z);85.1.1 5.1.1 函数的概念函数的概念v在语言中,所有的函数定义,包括主函数在语言中,所有的函数定义,包括主函数mainmain在内,都是平行的。也就是说,在一个函数的函在内,都是平行的。也就是说,在一个函数的函数体内不能再定义另一个函数,即不能嵌套定义。数体内不能再定义另一个函数,即不能嵌套定义。v但是函数之间允许相互调用,也允许嵌套调用。但是函数之间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己习惯上把调用者称为主调函数。函数还可以自己调用自己,称为递归调用。调用自己,称为递归调用。vmain main 函数是主函数,它可以调
6、用其它函数,而不函数是主函数,它可以调用其它函数,而不允许被其它函数调用。因此,语言程序的执行允许被其它函数调用。因此,语言程序的执行总是从总是从mainmain函数开始,函数开始,完成对其它函数的调用后完成对其它函数的调用后再返回到再返回到mainmain函数,最后由函数,最后由mainmain函数结束整个程函数结束整个程序。一个语言源程序必须有且只有一个主函数序。一个语言源程序必须有且只有一个主函数mainmain。95.1.2 5.1.2 函数的分类函数的分类v从函数定义的角度分类从函数定义的角度分类库函数。库函数由系统提供,用户无须定义,也不库函数。库函数由系统提供,用户无须定义,也不
7、必在程序中作类型说明,只需在程序前包含该函数原型必在程序中作类型说明,只需在程序前包含该函数原型的头文件,即可在程序中直接调用。在本书第二章对库的头文件,即可在程序中直接调用。在本书第二章对库函数作了详细说明,在函数作了详细说明,在C C程序中大量应用了库函数。例程序中大量应用了库函数。例如,如,printf printf、scanf scanf、getchar getchar、putcharputchar、getsgets、putsputs、strcatstrcat等函数。等函数。用户自定义函数。用户自定义函数是用户根据需要编用户自定义函数。用户自定义函数是用户根据需要编写的函数。用户自定义
8、函数不仅要在程序中定义函数本写的函数。用户自定义函数不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。型说明,然后才能使用。105.1.2 5.1.2 函数的分类函数的分类v根据函数调用是否有返回值分类根据函数调用是否有返回值分类有返回值函数。此类函数被调用执行完后将向调用者有返回值函数。此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值。如数学函数即属返回一个执行结果,称为函数返回值。如数学函数即属于此类函数。于此类函数。由用户定义的这种要返回函数值的函数,由用户定义的这种要返回函数值的
9、函数,必须在函数定义和函数说明中明确返回值的类型,如例必须在函数定义和函数说明中明确返回值的类型,如例5-15-1中的中的max1max1函数,执行完后将向它的调用者(函数,执行完后将向它的调用者(mainmain函函数)返回数)返回z z的值,并赋给变量的值,并赋给变量c c。无返回值函数。此类函数用于完成某项特定的处理任无返回值函数。此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。这类函数类似务,执行完成后不向调用者返回函数值。这类函数类似于其它语言的过程。由于函数无须返回值,用户在定义于其它语言的过程。由于函数无须返回值,用户在定义此类函数时可指定它的返回值为此类函数
10、时可指定它的返回值为“空类型空类型”,空类型的,空类型的说明符为说明符为“void”void”。115.1.2 5.1.2 函数的分类函数的分类#include/包含预处理命令main()/主函数void max2(int x,int y);/max2函数声明int a,b;/声明部分,定义变量printf(Please input two integers:n);/调用printf函数 scanf(%d,%d,&a,&b);/调用scanf函数 max2(a,b);/调用max2函数,无返回值 void max2(int x,int y)/定义max2函数 int z;if(xy)z=x;e
11、lse z=y;printf(max=%dn,z);125.1.2 5.1.2 函数的分类函数的分类v从主调函数和被调函数之间数据传送的角度分类从主调函数和被调函数之间数据传送的角度分类无参函数。函数定义、函数说明及函数调用中均不带参无参函数。函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。数。主调函数和被调函数之间不进行参数传送。此类函此类函数通常用来完成一组指定的功能,可以返回或不返回函数数通常用来完成一组指定的功能,可以返回或不返回函数值。如例值。如例5-25-2中中helloworldhelloworld函数,函数名后的小括号内没函数,函数名后的小括号内
12、没有参数,即为无参函数。有参数,即为无参函数。有参函数。也称为带参函数。在函数定义及函数说明时有参函数。也称为带参函数。在函数定义及函数说明时用到的参数,称为形式参数(简称为形参)。在函数调用用到的参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。进行时也必须给出参数,称为实际参数(简称为实参)。进行函数调用时,主调函数将把实参的值传送给形参,供被调函数调用时,主调函数将把实参的值传送给形参,供被调函数使用。如例函数使用。如例5-15-1中的中的max1max1或或max2max2函数都有两个整型的函数都有两个整型的参数参数x x和和y y。135.1.
13、3 5.1.3 函数的定义函数的定义v5.1.3.1 5.1.3.1 函数定义的形式函数定义的形式v函数定义也就是确定该函数应完成什么功能以及函数定义也就是确定该函数应完成什么功能以及如何实现这一功能。函数分为无参函数和有参函如何实现这一功能。函数分为无参函数和有参函数。数。v无参函数定义的一般格式如下所示:无参函数定义的一般格式如下所示:v类型标识符类型标识符 函数名函数名 ()()v v 声明部分声明部分v 语句部分语句部分v 145.1.3 5.1.3 函数的定义函数的定义v说明:说明:类型标识符和函数名合称为函数头,其中类型标识符类型标识符和函数名合称为函数头,其中类型标识符用于确定函
14、数类型即该函数的返回值类型,例如整型、用于确定函数类型即该函数的返回值类型,例如整型、实型、字符型等。省略类型标识符时默认为实型、字符型等。省略类型标识符时默认为intint类型。类型。函数名唯一标识函数的名称,通过函数名可实现函数的函数名唯一标识函数的名称,通过函数名可实现函数的调用。调用。C C语言中函数名必须是合法的标识符,即满足标语言中函数名必须是合法的标识符,即满足标识符的命名规则。在很多情况下都不要求无参函数有返识符的命名规则。在很多情况下都不要求无参函数有返回值,此时函数类型符可以写为回值,此时函数类型符可以写为voidvoid。由左、右大括号括起来的部分称为函数体。其中声明由左
15、、右大括号括起来的部分称为函数体。其中声明部分对函数内部用到的变量以及变量的类型进行说明,部分对函数内部用到的变量以及变量的类型进行说明,并说明该函数中所调用的函数类型。语句部分,规定函并说明该函数中所调用的函数类型。语句部分,规定函数中要执行的语句,由数中要执行的语句,由C C语言的基本语句组成,是函数语言的基本语句组成,是函数的核心部分。的核心部分。155.1.3 5.1.3 函数的定义函数的定义v有参函数定义的一般格式如下所示:有参函数定义的一般格式如下所示:v类型标识符类型标识符 函数名函数名 (形式参数类型说明形式参数类型说明 形式参形式参数表列数表列)v v 声明部分声明部分v 语
16、句部分语句部分v 函数名后括号中的内容是对形式参数的说明,明确指出函数名后括号中的内容是对形式参数的说明,明确指出该函数所带形式参数的个数及各参数的类型。形式参数该函数所带形式参数的个数及各参数的类型。形式参数表列可以为空,即定义的函数为无参函数,也可以有多表列可以为空,即定义的函数为无参函数,也可以有多个形参,当有多个形参时,各参数之间用逗号隔开。但个形参,当有多个形参时,各参数之间用逗号隔开。但无论有没有形参,函数名后的括号都不能丢掉。无论有没有形参,函数名后的括号都不能丢掉。165.1.3 5.1.3 函数的定义函数的定义#include int dif(int x,int y)int
17、z;z=x y?x-y:y-x;return(z);main()/主函数int a,b,c;/声明部分,定义变量printf(Please input two integers:n);/调用printf函数 scanf(%d,%d,&a,&b);/调用scanf函数 c=dif(a,b);/调用dif函数有参,有返回值并赋给变量cprintf(dif=%dn,c);/调用printf函数 175.1.3 5.1.3 函数的定义函数的定义v5.1.3.2 5.1.3.2 空函数空函数v这种函数什么也不做,只是用来占用一个位置,这种函数什么也不做,只是用来占用一个位置,在程序需要扩充功能的时候,用
18、一个编好的函数在程序需要扩充功能的时候,用一个编好的函数取代它。这类函数称为空函数,其定义形式为:取代它。这类函数称为空函数,其定义形式为:v类型标识符类型标识符 函数名函数名()()v v v函数体没有任何语句,调用此函数也不能完成任函数体没有任何语句,调用此函数也不能完成任何实际操作,空函数的功能是使程序结构清晰,何实际操作,空函数的功能是使程序结构清晰,需要时可以用其它函数代替。需要时可以用其它函数代替。18 5.2 5.2 函数原型与函数调用函数原型与函数调用本节内容本节内容 5.2.2 函数的参数函数的参数 5.2.3 函数的调用函数的调用 5.2.4 函数的返回值函数的返回值 5.
19、2.1 函数的原型函数的原型195.2.1 5.2.1 函数的原型函数的原型v编译程序在处理函数调用时,首先要获得执行被编译程序在处理函数调用时,首先要获得执行被调函数的接口信息,确认函数调用语句的正确性,调函数的接口信息,确认函数调用语句的正确性,然后进入被调函数执行。因此对被调函数有以下然后进入被调函数执行。因此对被调函数有以下要求:要求:被调函数必须是已经存在的用户自定义函数或者库函被调函数必须是已经存在的用户自定义函数或者库函数。数。如果调用的是库函数,在程序的开头必须用如果调用的是库函数,在程序的开头必须用#include#include 或或#include“*.h”#includ
20、e“*.h”将库函数所在头文件包含进来。将库函数所在头文件包含进来。头文件以字母头文件以字母h h为后缀,其中包含了库函数的原型说明。为后缀,其中包含了库函数的原型说明。如果使用的是自定义函数,在主调函数中应对被调函如果使用的是自定义函数,在主调函数中应对被调函数作原型说明。通常函数原型说明放在主调函数的开始数作原型说明。通常函数原型说明放在主调函数的开始位置或整个程序的开始。位置或整个程序的开始。205.2.1 5.2.1 函数的原型函数的原型v在语言程序中有两种方式可以说明函数原型。在语言程序中有两种方式可以说明函数原型。v函数类型函数类型 函数名函数名(数据类型数据类型1 1,数据类型,
21、数据类型2 2,);v函数类型函数类型 函数名函数名(数据类型数据类型1 1 形式参数形式参数1 1,数据类型数据类型2 2 形式形式参数参数2 2,);函数类型是该函数返回值的数据类型。如果是无值型则函数类型是该函数返回值的数据类型。如果是无值型则表示函数没有返回值。表示函数没有返回值。函数名为函数名为C C语言的合法标识符。语言的合法标识符。括号中的内容为该函数的形式参数说明。可以只有数据括号中的内容为该函数的形式参数说明。可以只有数据类型而没有形式参数类型而没有形式参数,也可以两者都有。也可以两者都有。21#include main()void calc(float x,float y,
22、char opr);/对被调函数calc的说明 float a,b;char opr;printf(Input expression:);scanf(%f%c%f,&a,&opr,&b);calc(a,b,opr);void calc(float x,float y,char opr)/函数calc的定义 switch(opr)case +:printf(%5.2f%c%5.2f=%6.2fn,x,opr,y,x+y);return;case -:printf(%5.2f%c%5.2f=%6.2fn,x,opr,y,x-y);return;case *:printf(%5.2f%c%5.2f=
23、%6.2fn,x,opr,y,x*y);return;case /:printf(%5.2f%c%5.2f=%6.2fn,x,opr,y,x/y);return;default:printf(Operator error!n);225.2.1 5.2.1 函数的原型函数的原型v实际在实际在C C语言中,如果有以下几种情况时可以在主语言中,如果有以下几种情况时可以在主调函数中省去对被调函数的说明:调函数中省去对被调函数的说明:当被调函数的函数定义出现在主调函数之前时。当被调函数的函数定义出现在主调函数之前时。如果已在所有函数定义之前,在函数外预先说明了各如果已在所有函数定义之前,在函数外预先说明
24、了各个函数的类型。个函数的类型。对库函数的调用不需要再作说明,但必须把该函数的对库函数的调用不需要再作说明,但必须把该函数的头文件用头文件用includeinclude命令包含在源文件前面。命令包含在源文件前面。在在Turbo CTurbo C环境下,如果被调函数的返回值是整型或环境下,如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明。在字符型时,可以不对被调函数作说明。在VCVC环境下,即环境下,即便被调函数的返回值是整型或字符型,当被调函数的函便被调函数的返回值是整型或字符型,当被调函数的函数定义出现在主调函数之后时,一定要先声明函数,再数定义出现在主调函数之后时,一定要先声明
25、函数,再使用。使用。235.2.2 5.2.2 函数的参数函数的参数v函数的参数可分为形参和实参两种。函数的参数可分为形参和实参两种。v在定义函数时函数名后括号内的变量表列称为在定义函数时函数名后括号内的变量表列称为形形式参数表列,简称为形参。式参数表列,简称为形参。只有在函数被调用时,该函数的形参才在内存中开辟空只有在函数被调用时,该函数的形参才在内存中开辟空间,一旦调用结束,所占用的存储空间也就随之释放。间,一旦调用结束,所占用的存储空间也就随之释放。因此,形参变量只在整个函数体内都可以使用。因此,形参变量只在整个函数体内都可以使用。v调用函数时函数名后括号内的变量表列称为调用函数时函数名
26、后括号内的变量表列称为实在实在参数表列,简称为实参参数表列,简称为实参。实参的值是在主调函数中给定的,在调用过程中将实参实参的值是在主调函数中给定的,在调用过程中将实参的值传递给相应的形参,从而实现主调函数向被调函数的值传递给相应的形参,从而实现主调函数向被调函数的数据传送。实参出现在主调函数中,进入被调函数后,的数据传送。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。实参变量也不能使用。245.2.2 5.2.2 函数的参数函数的参数v形参和实参具有以下特点:形参和实参具有以下特点:形参变量只有在被调用时才分配内存单元,在调用结形参变量只有在被调用时才分配内存单元,在调用结束时,
27、即刻释放所分配的内存单元。因此,形参只有在束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再函数内部有效。函数调用结束返回主调函数后则不能再使用该形使用该形 参变量。参变量。实参可以是常量、变量、表达式、函数等,在进行函实参可以是常量、变量、表达式、函数等,在进行函数调用时,它们都必须具有确定的值,以便把这些值传数调用时,它们都必须具有确定的值,以便把这些值传送给形参,而形参只能是变量。送给形参,而形参只能是变量。实参和形参在数量上,顺序上应严格一致,在类型上实参和形参在数量上,顺序上应严格一致,在类型上应相同或赋值兼容,否则会发生应相同或赋值兼容
28、,否则会发生“类型不匹配类型不匹配”的错误。的错误。注意:字符型与整型可以兼容。注意:字符型与整型可以兼容。255.2.2 5.2.2 函数的参数函数的参数函数调用过程中发生的数据传送是单向值传递。即只函数调用过程中发生的数据传送是单向值传递。即只能把实参的值传送给形参,而不能把形参的值反向地传能把实参的值传送给形参,而不能把形参的值反向地传送给实参,实参到形参的传递是单向的。送给实参,实参到形参的传递是单向的。vC C语言的参数传递机制有两种:值传递和地址传递。语言的参数传递机制有两种:值传递和地址传递。值传递的特点是:先对实参求值,然后将其值传送给相值传递的特点是:先对实参求值,然后将其值
29、传送给相应的形参,形参的作用范围仅在该函数内,即函数的形应的形参,形参的作用范围仅在该函数内,即函数的形式参数作为函数的局部变量处理,不会影响实参变量的式参数作为函数的局部变量处理,不会影响实参变量的值,实参向形参的传递是单向的。值,实参向形参的传递是单向的。地址传递的特点是:实参是地址量(如数组名地址传递的特点是:实参是地址量(如数组名指针),指针),实参传递地址给形参,这样形参和实参存在于一个地址实参传递地址给形参,这样形参和实参存在于一个地址空间,被调函数对形参做的任何操作都会影响主调函数空间,被调函数对形参做的任何操作都会影响主调函数中的实参变量,实参与形参的传递是双向的。中的实参变量
30、,实参与形参的传递是双向的。265.2.2 5.2.2 函数的参数函数的参数#include void swap(int x,int y)int z;z=x;x=y;y=z;printf(x=%d,y=%d,x,y);main()int a,b;printf(please input a,b:);scanf(%d,%d,&a,&b);swap(a,b);printf(na=%d,b=%dn,a,b);275.2.3 5.2.3 函数的调用函数的调用v5.2.3.1 5.2.3.1 函数调用格式函数调用格式v若被调函数是有参函数,则直接使用函数名和实若被调函数是有参函数,则直接使用函数名和实参的
31、方法,其一般格式为:参的方法,其一般格式为:v函数名(实参表列)函数名(实参表列)v函数调用的过程中,将主调函数中的实参值赋给函数调用的过程中,将主调函数中的实参值赋给被调函数中对应的形式参数,然后进入被调函数被调函数中对应的形式参数,然后进入被调函数执行,若被调函数是有返回值函数,则执行结束执行,若被调函数是有返回值函数,则执行结束后可将结果返回给主调函数。后可将结果返回给主调函数。v如若调用无参函数,其一般格式为:如若调用无参函数,其一般格式为:v函数名()函数名()285.2.3 5.2.3 函数的调用函数的调用#include int dif(int x,int y)int z;z=x
32、 y?x-y:y-x;return(z);main()int m,n,diff;m=10;n=4;diff=dif(m,n);printf(dif=%d n,diff);295.2.3 5.2.3 函数的调用函数的调用v上述函数是有参函数,在调用时需注意以下几点:上述函数是有参函数,在调用时需注意以下几点:实参个数和形参个数应该相同,在传递过程中按顺序实参个数和形参个数应该相同,在传递过程中按顺序对应。对应。实参的类型必须和形参类型一一对应。如果不同,将实参的类型必须和形参类型一一对应。如果不同,将实参类型转换成形参类型然后传递。实参类型转换成形参类型然后传递。实参可以是常量、变量或者表达式,
33、而形参只能是变实参可以是常量、变量或者表达式,而形参只能是变量。量。实参可以和形参同名。实参可以和形参同名。如果有多个实参,实参间用逗号隔开,并需注意实参如果有多个实参,实参间用逗号隔开,并需注意实参的求值顺序。的求值顺序。305.2.3 5.2.3 函数的调用函数的调用v5.2.3.2 5.2.3.2 函数调用函数调用作为语句的函数调用。其一般格式为:作为语句的函数调用。其一般格式为:函数名(实在参数表);函数名(实在参数表);这种方法经常用于调用一个可以忽略返回值或没有返回这种方法经常用于调用一个可以忽略返回值或没有返回值的函数。值的函数。作为表达式的函数调用。凡是表达式可以出现的地方作为
34、表达式的函数调用。凡是表达式可以出现的地方都可以出现函数调用。其一般格式为:都可以出现函数调用。其一般格式为:变量名变量名=函数表达式函数表达式这种方式通常用于调用带返回值的函数。这种方式通常用于调用带返回值的函数。作为参数的函数调用。函数作为另一个函数调用的实作为参数的函数调用。函数作为另一个函数调用的实际参数出现。际参数出现。这种情况是把该函数的返回值作为实参进行传递,因此这种情况是把该函数的返回值作为实参进行传递,因此要求该函数必须是有返回值的。要求该函数必须是有返回值的。315.2.3 5.2.3 函数的调用函数的调用#include int cube(int x)/定义cube函数
35、return(x*x*x);main()int a;printf(nEnter an integer number:);scanf(%d,&a);printf(%d*%d*%d=%dn,a,a,a,cube(a);325.2.4 5.2.4 函数的返回值函数的返回值v函数的返回值是指函数调用结束后,由被调函数函数的返回值是指函数调用结束后,由被调函数返回给主调函数的值。返回给主调函数的值。v被调函数运算的结果通过被调函数运算的结果通过returnreturn语句返回主调语句返回主调函数。函数。return return 语句的一般形式为:语句的一般形式为:vreturn return 表达式;
36、表达式;v或者为:或者为:vreturn(return(表达式表达式);v该语句的功能:该语句的功能:终止被调函数的运行,返回主调函数;终止被调函数的运行,返回主调函数;335.2.4 5.2.4 函数的返回值函数的返回值若有返回值,将返回值带回主调函数。其中若有返回值,将返回值带回主调函数。其中“表达式表达式”可以是常量可以是常量变量变量函数调用等。一个函数中允许有函数调用等。一个函数中允许有多个多个returnreturn语句,即函数可以有多个出口。但每次调用语句,即函数可以有多个出口。但每次调用只能有一个只能有一个return return 语句被执行,因此最多只能返回一语句被执行,因此
37、最多只能返回一个函数值。个函数值。v函数返回值的类型应和定义函数时的函数类型函数返回值的类型应和定义函数时的函数类型保持一致。如果两者不同,则以函数类型为准,保持一致。如果两者不同,则以函数类型为准,自动对返回值进行类型转换。即函数类型决定函自动对返回值进行类型转换。即函数类型决定函数返回值的类型。数返回值的类型。345.2.4 5.2.4 函数的返回值函数的返回值#include main()int dif(float x,float y);float a,b;int c;printf(please input a,b:);scanf(%f,%f,&a,&b);c=dif(a,b);prin
38、tf(difference is%dn,c);int dif(float x,float y)/函数类型为整型 float z;/z为实型变量 z=xy?x-y:y-x;return(z);355.2.4 5.2.4 函数的返回值函数的返回值v程序中程序中difdif函数还可以定义成下面的形式:函数还可以定义成下面的形式:int dif(float x,float y)int dif(float x,float y)float z;float z;if(xy)return(z=x-y);if(xy)return(z=x-y);else return(z=y-x);else return(z=y
39、-x);v如果函数值为整型,在函数定义时可以省去类如果函数值为整型,在函数定义时可以省去类型说明。型说明。v如果函数没有返回值,应明确定义为如果函数没有返回值,应明确定义为“空类型空类型”,类型说明符为,类型说明符为“void”void”。v为了使程序有良好的可读性并减少出错,凡不要为了使程序有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型。求返回值的函数都应定义为空类型。365.3 5.3 函数的嵌套调用函数的嵌套调用v语言规定,函数中不允许嵌套定义函数,但是语言规定,函数中不允许嵌套定义函数,但是语言允许在一个函数的调用过程中调用另一个语言允许在一个函数的调用过程中调用另一个
40、函数,即一个被调函数中再调用其他函数,这称函数,即一个被调函数中再调用其他函数,这称为函数的嵌套调用。为函数的嵌套调用。37mainmainmainmain函数函数函数函数 调用函数调用函数调用函数调用函数 A;A;A;A;5.3 5.3 函数的嵌套调用函数的嵌套调用v嵌套的执行过程嵌套的执行过程函数函数函数函数 B B B B 函数函数函数函数 A A A A 调用函数调用函数调用函数调用函数 B B B B;38#include int dif(int x,int y,int z);/dif函数的说明int max(int x,int y,int z);/max函数的说明int min(i
41、nt x,int y,int z);/min函数的说明void main()int a,b,c,d;printf(please input a b c:);scanf(%d%d%d,&a,&b,&c);d=dif(a,b,c);/调用dif函数 printf(Max-Min=%dn,d);int dif(int x,int y,int z)/定义dif函数,求最大值与最小值之差 return max(x,y,z)-min(x,y,z);/调用max和min函数395.3 5.3 函数的嵌套调用函数的嵌套调用int max(int x,int y,int z)/定义max函数,求三个数中最大值
42、int r;r=xy?x:y;return(rz?r:z);int min(int x,int y,int z)/定义min函数,求三个数中最小值 int r;r=xy?x:y;return(r 1n 1时时 v递归结束条件:当递归结束条件:当n=1n=1或或n=0n=0时,时,n!=1n!=1435.4 5.4 函数的递归调用函数的递归调用#include void dtoo(int x)/定义递归函数dtoo unsigned int m;m=x%8;/除8取余数x=x/8;/除8求商if(x!=0)dtoo(x);printf(%d,m);main()unsigned int n;pri
43、ntf(please decimal digit n:);scanf(%d,&n);/输入十进制整数printf(%d)10=(,n);dtoo(n);/调用递归函数dtooprintf()8n);445.4 5.4 函数的递归调用函数的递归调用#include float fac(int n)float f=0;if(n0)printf(n1n1时,先把上面时,先把上面n-1n-1个圆盘从个圆盘从A A移到移到B B,然后将然后将n n号盘从号盘从A A移到移到C C,再将再将n-1n-1个盘从个盘从B B移到移到C C。即把求解即把求解n n个圆盘的个圆盘的HanoiHanoi问题转化为求
44、解问题转化为求解n-1n-1个圆盘的个圆盘的HanoiHanoi问题,依次类问题,依次类推,直至转化成只有一个圆盘的推,直至转化成只有一个圆盘的HanoiHanoi问题问题515.4 5.4 函数的递归调用函数的递归调用v函数函数movemove完成将第完成将第k k个盘子从个盘子从A A移动到移动到C Cmove(int no,char from,char to);move(int no,char from,char to);no:no:盘子编号,盘子编号,from:from:源柱源柱 to:to:目的柱目的柱v函数函数hanoihanoi完成将完成将n n个盘子从个盘子从A A移动到移动到
45、C Chanoi(int n,char one,char two,char three)hanoi(int n,char one,char two,char three)借助借助twotwo将将n n个盘子从个盘子从oneone移动到移动到threethree525.4 5.4 函数的递归调用函数的递归调用v将将n n个盘子借助个盘子借助B B从从A A移动到移动到C C,实现过程如下:,实现过程如下:v函数调用函数调用 AA one one,BB twotwo,CC threethreev步骤步骤1 1:hanoi(n-1,one,three,two);hanoi(n-1,one,three
46、,two);借助借助C C柱子将柱子将n-1n-1个盘子从个盘子从A A移到移到B B v步骤步骤2 2:move(n,one,three);move(n,one,three);将第将第n n个盘子从个盘子从A A柱子移动到柱子移动到C C柱子柱子v步骤步骤3 3:hanoi(n-1,two,one,three);hanoi(n-1,two,one,three);借助借助A A柱子将柱子将n-1n-1个盘子从个盘子从B B移到移到C C53函数的递归调用函数的递归调用v例例5.125.12:汉诺塔:有汉诺塔:有A A,B B,C C三个塔座,三个塔座,A A上套有上套有n n个直径不同的圆盘,
47、按直径从小到大叠放,形如个直径不同的圆盘,按直径从小到大叠放,形如宝塔宝塔,编号编号1 1,2 2,33n n。要求将要求将n n个圆盘从个圆盘从A A移移到到C C,叠放顺序不变,移动中遵循下列原则:叠放顺序不变,移动中遵循下列原则:每次只能移一个圆盘每次只能移一个圆盘圆盘可在三个塔座上任意移动圆盘可在三个塔座上任意移动任何时刻,每个塔座上不能将大盘压到小盘上任何时刻,每个塔座上不能将大盘压到小盘上#include void move(int no,char from,char to)printf(Move%3d:%c-%cn,no,from,to);void hanoi(int n,cha
48、r one,char two,char three)if(n=1)move(n,one,three);else hanoi(n-1,one,three,two);move(n,one,three);hanoi(n-1,two,one,three);void main()int n;printf(Input the number of diskes:);scanf(%d,&n);printf(The step to moving%3d diskes:n,n);hanoi(n,A,B,C);545.4 5.4 函数的递归调用函数的递归调用55 5.5 5.5 调用与被调用函数间的数据传递调用与被调
49、用函数间的数据传递本节内容本节内容调用与被调用函数间的地址传递调用与被调用函数间的地址传递 调用与被调用函数间的数值传递调用与被调用函数间的数值传递56调用与被调用函数间的数值传递调用与被调用函数间的数值传递v函数调用可以实现调用函数与被调用函数之间数函数调用可以实现调用函数与被调用函数之间数据的传递。一般采用三种方式进行数据传递。据的传递。一般采用三种方式进行数据传递。vreturnreturn语句是其中一种方式,通过语句是其中一种方式,通过returnreturn语句可语句可以将一个函数值返回到主调函数中;以将一个函数值返回到主调函数中;v另外还可以使用全局变量在函数间传递多个数据,另外还
50、可以使用全局变量在函数间传递多个数据,这将在后边详细介绍;这将在后边详细介绍;v使用最多的是借助形参和实参实现数据的传递。使用最多的是借助形参和实参实现数据的传递。在在C C语言中,实参和形参之间的传递有两种方法:语言中,实参和形参之间的传递有两种方法:“值传递值传递”和和“地址传递地址传递”。57调用与被调用函数间的数值传递调用与被调用函数间的数值传递v5.5.1.1 5.5.1.1 普通变量作函数参数普通变量作函数参数v作为实参的变量在内存中占有存储空间,而形参作为实参的变量在内存中占有存储空间,而形参只有在被调用时才分配空间,调用结束该空间就只有在被调用时才分配空间,调用结束该空间就被释