合工大计算机学院 程序设计 04第四章 函数.ppt
第四章 函数,函数的声明与调用 参数传递方式 标识符的作用域 变量的生存期 递归程序设计 C+语言常用库函数,4.1 C+语言的函数 一、函数的建立与使用,函数的建立函数声明:定义函数的名字、执行的语句序列、传递和使用的数据参数、返回值等;函数的使用函数调用:指明函数去“做什么”;函数调用的控制流程:如右图,函数调用程序(主调函数),调用F,调用F,被调用函数F,例1:,#include float max(float x,float y)float z;/求两个数的最大值if(x=y)z=x;else z=y;return z;int main()float i,j,k;/用户输入的三个数float temp;/临时最大者cout i j k;/用户输入三个数/找出最大数存放在temp中temp=max(i,j);/main()是主调函数,max()是被调函数temp=max(temp,k);/输出找到的最大数cout The maximum number is temp n;return 0;,3.说明,C+语言中,函数是平行的,相互独立。一个函数不从属于另一个函数,即函数不能嵌套定义例:fun1()fun2()这是不合法的,无法通过编译,从函数声明的角度看:标准函数(库函数):由C+语言的集成开发环境提供,存放在库(Library)函数中,用户在链接相应的库函数头文件后便可以直接使用。用户自定义的函数从函数的形式看:无参函数:调用该函数时,主调函数不需函数要将数据传递给被调用函数,只执行指定的一组操作有参函数:主调需传递数据给被调函数,4.2 函数的声明与调用 一、函数声明,函数声明(函数的定义性声明)函数类型 函数名(形式参数表)说明部分(变量声明)语句部分 函数类型指函数返回值的数据类型,由return语句获得:float max(float x,float y)return xy?x:y;若函数定义时没有说明函数类型,则缺省认为函数返回类型是int main()若函数无返回值,则应明确定义函数类型为void void handle(),函数名是标识符函数名后一定要有一对圆括号(),这是函数的标志,使函数与其他标识符名区分开来形式参数用于接收从主调函数传给这个函数的数据一般形式:(数据类型 变量1,数据类型 变量2,)形参个数不受限制函数体声明部分:用于声明在函数中使用到的变量语句部分:在函数中用于实现某项任务的语句序列空函数:函数体为空(没有语句,但 不能省略),二、函数调用,函数调用的一般形式:当作表达式使用函数名(实际参数表)实际参数出现在函数调用表达式中,是函数调用时,实际使用的参数一般形式:(表达式1,表达式2,)实际参数表是用逗号分隔的表达式列表,其中每一个表达式称为实际参数,有时也简称为实参。在函数调用时,需要将实际参数的值传送给对应位置的形式参数实际参数与形式参数必须一一对应,位置、个数以及数据类型都匹配 例:p82,2.函数调用表达式,函数调用作为一个表达式,其类型是函数返回值的类型 函数调用可用于任何表达式可以出现的地方例1:if(max(i,j)k)例2:temp=max(max(i,j),k);3.函数的嵌套调用:在调用一函数的过程中,又调用另一函数C+允许函数的嵌套调用不允许函数的嵌套定义,4.对被调用函数的声明和函数原型,函数使用必须遵循“先声明、后使用”原则,因为C+编译系统在编译时必须先知道该函数实现的形式(接口形式)。对于用户自定义函数如果被调用函数的定义位于主调函数的后面,则必须在调用函数表达式之前对被调用函数做引用性声明函数的定义性声明:完整的、独立的函数单位,包括函数类型、函数名、形参及其类型,并且具有完整的函数体;函数的引用性声明(函数原型):无函数体部分,一般形式:函数定义的首部;函数原型必须与函数定义保持一致,例:,#include int main()float i,j,k;float temp;cout i j k;temp=max(i,j);temp=max(temp,k);cout=y)z=x;else z=y;return z;,float max(float x,float y);,函数原型:float max(float x,float y);float max(float,float);float max(float t,float k);,4.3 参数传递,一、参数传递方式 主调函数与被调函数的数据交换:由参数传递与返回值实现按值调用:单项的参数传递按引用调用:双向的参数传递二、按值调用(传值,按拷贝调用)单向的,实际参数形式参数,传递的是参数的值例:p91#include cout i is i n;int square(int x)cout j is j n;/求一个整数的平方 return 0;x=x*x;return x;int main()int i,j;i=8;j=square(i);,8,64,64,64,三、缺省参数,C+语言允许在函数原型或函数定义中为形式参数指定缺省值,具有缺省值的形式参数称缺省形参用初值表达式定义缺省值缺省行参必须从右边开始定义int func(int a,float b,int c=0);若在函数调用时指定了形式参数对应的实际参数,则形式参数使用实际参数的值,否则未指定相应的实际参数则形式参数使用缺省值。,例2:,#include#include/给出函数原型double distance(double x1,double y1,double x2=0,double y2=0);int main()cout(1,2)to(0,0)is distance(1,2)n;cout(-1.5,2)to(1.5,-2)is distance(-1.5,2,1.5,-2)n;return 0;/计算两点之间的距离double distance(double x1,double y1,double x2,double y2)double x,y;x=x2-x1;y=y2-y1;return sqrt(x*x)+(y*y);,4.4 生存期与作用域 一、变量的两个性质,生存期:(从时间角度考虑)变量的生存期是指在程序运行过程中变量占存储空间的时限作用域:(从空间角度考虑)指在变量占用存储空间的时间内变量的名字能被引用的区域,即变量名作用的有效范围。在变量的作用域中变量必然存在在变量的生存期中变量不一定有效,二、全局变量和局部变量,局部变量:在一个块语句 内部定义的变量作用域:本块语句中。块语句嵌套时,内层的同名变量有效,而外层的同名变量被屏蔽。不同函数中使用同名变量,代表不同对象,互不相干例:void func(int x)形式参数x的作用域int y=x+1;外层变量y的作用域int y=x+2;内层变量y的作用域int z=x+3;内层变量z的作用域y=y*y;z=z*z;cout x”y”z”n”;int z=x+4;外层变量z的作用域y=y+y;z=z+z;cout x”y”z”n”;,生存期:局部变量是当程序的控制流程进入定义该变量的块语句时,才为其分配一块临时的存储空间,当程序的控制流程退出该程序块时,临时占用的存储空间被释放。初始化:无显式初始化式,其初值是一个不确定的值。显示初始化时,每次流程进入块函数时,分配内存空间,都重新对局部变量初始化,2.全局变量:在函数之外定义的变量,作用域:从定义变量开始到本源程序文件结束。生存期:全局变量在整个程序的运行期中都存在初始化:无显式初始化式,其初值会被清0。显示初始化时,对全局变量的初始化在编译时一次完成。同名的全局变量与局部变量:在局部变量的作用域内,全局变量被屏蔽,直接使用该名字,用的是局部变量,但可用:作用域运算符引用同名全局变量,例:,int y=8;void func(int x)int y=x+1;:y=:y*y;cout y”:y”n”;int main()func(3);cout y”n”;return 0;,三、变量的存储类别,1.存储方式从生存期(时间)来分,有两种存储方式静态存储方式:在程序运行期间占用固定存储空间动态存储方式:运行时,根据需要动态分配存储空间内存中,供用户使用的存储空间:变量的定义:数据存储类别 数据类型 变量名(=初值);,程序区,静态存储区,动态存储区,2.数据存储类别,例:,#include void grow()int age=30;age=age+1;cout My age is age n;return;int main()for(int i=1;i=3;i=i+1)grow();return 0;age不是静态变量的运行结果:age是静态局部变量的运行结果:My age is 31 My age is 31My age is 31 My age is 32My age is 31 My age is 33,static,4.5 递归程序设计,在函数定义中,一个函数直接或间接地调用自己,称递归调用,这类函数为递归函数。1)直接递归2)间接递归f(int x)f1()f2()f(x-1);f2();f1();递归调用是无终止的自身调用,因此在递归函数中应该用if语句或其它分支语句,判断当某些条件成立时结束递归调用,例:,/功能:使用递归程序计算Fibonacci序列。#include int fibonacci(int n)int result;if(n 2)result=1;else result=fibonacci(n-1)+fibonacci(n-2);return result;int main()int loop;/循环变量/输出Fibonacci序列的前6个数for(loop=0;loop=5;loop=loop+1)cout fibonacci(loop);cout n;return 0;,int fibonacci(int n)int result,i,pre1,pre2;result=1;i=2;pre2=1;while(i=n)pre1=pre2;pre2=result;result=pre1+pre2;i+;return result;,设n为5,则有:F(5)=F(3)+F(4)=F(1)+F(2)+F(2)+F(3)=F(1)+F(0)+F(1)+F(0)+F(1)+F(1)+F(2)=F(1)+F(0)+F(1)+F(0)+F(1)+F(1)+F(0)+F(1)=1+1+1+1+1+1+1+1=8,分析如下:,例:梵塔问题,盘按由小到大的顺序标上号码1n。开始时n个盘全套在A柱上,且小的放在大的上面,如图所示。游戏要求按下列规则将所有的盘从A柱移到C柱,在移动过程中可以借助另一个B柱。规则1:每次只能移动柱最上面的一个盘;规则2:任何盘都不得放在比它小的盘上。A B C 1 2 n,递归思路:把A上的n个盘运到C上先把n-1个盘从A搬到B,借助C把A上剩下的最大的一个盘搬到C再把n-1个盘从B搬到C,借助A当n=1时,直接从A搬到C即可,程序,#include/将disk_num个盘从from柱移到to柱,可以借助aux柱void move_tower(int disk_num,char from,char to,char aux)if(disk_num=1)/仅有一个盘时,直接从from柱移到to柱cout Move disk1 from from to to n;else/将disk_num-1个盘从from柱移到aux柱,借助于to柱move_tower(disk_num-1,from,aux,to);/将最下的盘从from柱移到to柱cout Move disk disk_num from from to to n;/将disk_num-1个盘从aux柱移到to柱,借助于from柱move_tower(disk_num-1,aux,to,from);return;int main()move_tower(4,A,C,B);return 0;,