C高级语言程序设计第5章.ppt
C+高级语言程序设计,第5章 函数北京邮电大学信息与通信工程学院,程序设计中,把具有一定功能的程序模块用函数或类来实现。,2023/11/7,北京邮电大学信息与通信工程学院,-2-,第5章 函数,内容函数定义、声明、函数的调用、函数参数传递机制函数的特殊形式,包括递归函数、内联函数、带默认参数值的函数标识符的作用域和可见性变量的存储类型和生存期,2023/11/7,北京邮电大学信息与通信工程学院,-3-,5.1 函数概述,结构化程序设计,将整个程序自顶向下分为若干个程序模块,每个模块用来实现一个特定的功能。C+中的模块以函数和类的形式实现。函数是具有一定功能又经常使用的相对独立代码段。无论是面向过程的程序设计还是面向对象的程序设计,函数都是一种实现算法的重要形式。,2023/11/7,北京邮电大学信息与通信工程学院,-4-,5.1 函数概述,函数接口(规定接口形式)函数名(命名规则与变量相同,见名知意)函数类型(返回值类型)形式参数表函数体(实现算法三种基本结构组合而成)常用的函数C+的库函数自定义的函数,2023/11/7,北京邮电大学信息与通信工程学院,-5-,5.1.1 自定义函数概述,编程者在处理具体问题时,将程序中多处使用的、实现一定功能的特定代码段定义成函数。这样的函数称为自定义函数。在同一个程序中,一个函数只能定义一次。一般是通过函数调用来使用函数。函数调用需要指定函数名并且提供被调用函数所需的信息(即函数参数)。,2023/11/7,北京邮电大学信息与通信工程学院,-6-,5.1.1 自定义函数概述,例如要打印某一年某一月的月历,2023/11/7,北京邮电大学信息与通信工程学院,-7-,5.1.2 库函数概述,C+标准库提供了丰富的函数集合,可以进行常用的数学计算、字符串操作、字符操作、输入/输出、错误检查和许多其他操作。要熟悉C+标准库提供的类和函数集合,不要事事从头做起,要尽可能利用C+标准库提供的函数,以便减少程序开发的时间。这是程序设计的技巧之一。,2023/11/7,北京邮电大学信息与通信工程学院,-8-,5.1.2 库函数概述,数学库函数实现常见的数学计算使用时,在程序中嵌入cmath头文件,按对应库函数的接口形式写调用语句。调用数学函数:函数名(参数1,参数n)例如:double x;x=sqrt(900.0);coutx;数学函数库中的多数函数都返回double类型结果。,2023/11/7,北京邮电大学信息与通信工程学院,-9-,2023/11/7,北京邮电大学信息与通信工程学院,-10-,常用数学库函数,2023/11/7,北京邮电大学信息与通信工程学院,-11-,#include#include using namespace std;int main()cout a b c;if(a!=0),调用函数 或主调函数,被调函数,库函数,2023/11/7,北京邮电大学信息与通信工程学院,-12-,#include using namespace std;float CircleArea(float r);int main()/manage circle computation cout MyRadius;float Area=CircleArea(MyRadius);cout Circle has area Area;return 0;/CircleArea():compute area of radius r circlefloat CircleArea(float r)const float Pi=3.1415;return Pi*r*r;,自定义函数,5.2 函数定义及使用,2023/11/7,北京邮电大学信息与通信工程学院,-13-,一个C+控制台程序可以由一个主函数(main()函数)和若干子函数构成。主函数main()是程序执行的开始点,由主函数调用子函数,子函数还可以再调用其他子函数。调用其他函数的函数被称为主调函数。被其他函数调用的函数称为被调函数。一个函数既可以是主调函数,又可以是被调函数(main()除外)。,5.2.1 函数的定义,每一个函数都是一个具有一定功能的语句模块,函数定义的语法形式:返回值类型 函数名(形式参数表)函数体(变量声明和执行语句),2023/11/7,北京邮电大学信息与通信工程学院,-14-,约定接口形式,函数体完成功能,int maximum(int x,int y)int maxv;maxv=x=y?x:y;return maxv;,2023/11/7,北京邮电大学信息与通信工程学院,-15-,float CircleArea(float r)const float Pi=3.1415;return Pi*r*r;,5.2.1 函数的定义,函数体,返回值语句,局部变量定义,形式参数,函数类型,函数名,5.2.1 函数的定义,函数名是函数体代码段的外部标识符函数定义之后,即可通过函数名调用函数。例:/Sum():compute sum of integers in a.bint Sum(int a,int b)int Total=0;for(int i=a;i=b;+i)Total+=i;return Total;,2023/11/7,北京邮电大学信息与通信工程学院,-16-,5.2.1 函数的定义,函数的形式参数表,简称形参表 形式:(类型1 形式参数1,类型n 形式参数n),2023/11/7,北京邮电大学信息与通信工程学院,-17-,/Sum():compute sum of integers in a.bint Sum(int a,int b)int Total=0;for(int i=a;i=b;+i)Total+=i;return Total;,形式参数表示主调函数和被调函数之间需要交换的信息(1)传给被调函数的待处理的数据;(2)控制被调函数执行操作的信息;(3)被调函数执行的结果。形式参数表从参数的类型、个数、排列顺序上规定了主调函数和被调函数之间信息交换的形式。float func(int k,int b,float x)return k*x+b;,2023/11/7,北京邮电大学信息与通信工程学院,-18-,5.2.1 函数的定义,如果函数之间没有需要交换的信息,也可以没有形参,形参表内写void或空着。int Read()cout Response;return Response;,2023/11/7,北京邮电大学信息与通信工程学院,-19-,5.2.1 函数的定义,5.2.1 函数的定义,函数体是实现函数功能的代码部分变量声明完成函数功能的语句两部分从组成结构看,函数体是由程序的三种基本控制结构即顺序、选择、循环结构组合而成的。,2023/11/7,北京邮电大学信息与通信工程学院,-20-,int Sum(int a,int b)int Total=0;for(int i=a;i=b;+i)Total+=i;return Total;,2023/11/7,北京邮电大学信息与通信工程学院,-21-,函数是由函数名、函数类型、形参表和函数体四部分组成的,使用时通过函数名和参数表调用函数.,例:编写一个函数cube,计算整数的立方。调用函数cube计算从1到10相邻整数的立方差。,2023/11/7,北京邮电大学信息与通信工程学院,-22-,尽可能避免在循环体内调用函数!,/计算整数的立方#include using namespace std;int cube(int);/函数原型声明void main()int last,cb;last=1;cout the difference of cube:endl;for(int x=2;x=10;x+)cb=cube(x);cout cb-last;last=cb;cout endl;,/函数定义int cube(int y)return y*y*y;,2023/11/7,北京邮电大学信息与通信工程学院,-23-,/在三个浮点中找出最大值#include using namespace std;float maximum(float x,float y,float z);/函数原型声明void main()float a,b,c;cout a b c;/调用maximum函数,a,b,c为实际参数 cout Maximum is:maximum(a,b,c)endl;/函数调用,例:在三个浮点中确定最大值,使用自定义函数maximum完成。,2023/11/7,北京邮电大学信息与通信工程学院,-24-,/maximum函数定义/函数的形式参数x,y,zfloat maximum(float x,float y,float z)float max;max=x=y?x:y;max=max=z?max:z;return max;,5.2.1 函数的定义,注意如果没有函数原型声明,要先写函数定义,后调用函数。C+语言不允许函数嵌套定义,所有函数的定义都是自成一体,即函数体中只包含实现其自身功能的基本语句,不可包含其他函数的定义体。,2023/11/7,北京邮电大学信息与通信工程学院,-25-,5.2.2 函数原型,引用函数之前,要先指定函数的接口形式函数原型函数定义函数原型声明格式:函数类型 函数名(形式参数表);例:int Max(int a,int b);函数原型声明使编译器获得关于函数名称、函数类型、函数形参个数、形参类型和形参顺序的信息。函数调用时,编译器根据函数原型声明验证函数调用正确与否。,2023/11/7,北京邮电大学信息与通信工程学院,-26-,5.2.2 函数原型,程序中,如果调用自定义的函数,且函数定义在后,调用在先,则必须在调用函数之前有函数原型声明。void subfun1(int x,float a,float b);/原型声明main()int x=20;float a=1.0f,b=0.5f;subfun1();/函数调用 void subfun1(int x,float a,float b)/函数定义,2023/11/7,北京邮电大学信息与通信工程学院,-27-,5.2.2 函数原型,如果是函数定义在先,调用在后,则不必进行函数原型声明。因为编译器已经从函数定义得到关于函数的信息。void subfun1(int x,float a,float b)/函数定义 main()subfun1(i,f1,f2);/函数调用,2023/11/7,北京邮电大学信息与通信工程学院,-28-,5.2.2 函数原型,源文件中,如果在所有函数定义体之外声明函数原型,则该函数可被位于其原型声明之后的所有函数调用。,2023/11/7,北京邮电大学信息与通信工程学院,-29-,void subfun1();/原型声明main()subfun1();/函数调用 void subfun2()subfun1();/函数调用 void subfun1()/函数定义,main()void subfun1();/函数原型声明 subfun1();/函数调用 void subfun2()subfun1();/函数调用,void subfun1(),2023/11/7,北京邮电大学信息与通信工程学院,-30-,错误,编译器不识别sunfun1标识符。,5.2.2 函数原型,库函数的声明在相应库的头文件中,使用库函数时要包含对应的头文件。例:#include 调用数学库函数:sqrt()sin()abs(),2023/11/7,北京邮电大学信息与通信工程学院,-31-,2023/11/7,北京邮电大学信息与通信工程学院,-32-,常用C+标准库头文件cassert包含增加诊断以帮助程序调试的宏和信息cctype 包含测试某些字符属性的函数原型和将小写字母变为 大写字母、将大写字母变为小写字母的函数原型cmath 包含数学库函数的函数原型cstdio 包含标准输入/输出库函数的函数原型及其使用的信息cstdlib 包含将数字变为文本、将文本变为数字、内存分配、随机数和各种其他工具函数的函数原型cstring 包含C语言方式的字符串处理函数原型ctime 包含操作时间和日期的函数原型和类型iostream 包含标准输入/输出函数原型iomanip 包含能够格式化数据流的流操纵运算子的函数原型fstream 包含和磁盘文件读/写有关的函数原型,5.2.2 函数原型,例5-2 计算3个整数绝对值的平均值。,2023/11/7,北京邮电大学信息与通信工程学院,-33-,2023/11/7,北京邮电大学信息与通信工程学院,-34-,/例5-2 计算3个数绝对值的平均值#include#include using namespace std;int CalAbsMean(int a,int b,int c);/自定义函数的原型声明 void main()int a,b,c;coutabc;cout绝对值的均值为:CalAbsMean(a,b,c)endl;int CalAbsMean(int a,int b,int c)int sum=abs(a)+abs(b)+abs(c);sum/=3;return sum;,运行结果:输入 a,b,c:-10 20-30 绝对值的均值为:20,5.2.3 return语句,return语句使程序执行流程从被调函数返回主调函数,有两种形式:(1)不返回值的形式 return;(2)返回值的形式 return 表达式;,2023/11/7,北京邮电大学信息与通信工程学院,-35-,int Sum(int a,int b)int Total=0;for(int i=a;i=b;+i)Total+=i;return Total;,void DisplayMessage()cout只显示确定信息的简单函数不带参数endl;return;,函数返回值类型规定了函数返回给主调函数的值的类型,也称为函数类型。当被调函数只需要把一个数值结果返回给主调函数时,使用return语句返回比较合适。由return语句返回的值的类型必须与函数返回值类型一致。若表达式的结果与函数类型不一致,不能通过编译,需要作强制类型转换,将表达式的类型强制成与函数类型。例如,如果mean是float型,而函数是int型,则return语句应为:return(int)mean;,2023/11/7,北京邮电大学信息与通信工程学院,-36-,int Sum(int a,int b)int Total=0;for(int i=a;i=b;+i)Total+=i;return Total;,5.2.3 return语句,5.2.3 return语句,注意如果不需要向主调函数返回值,函数可以定义成无类型的,函数类型写成void,函数结束时也不必用return语句。例:void display()cout“no return”endl;,2023/11/7,北京邮电大学信息与通信工程学院,-37-,5.2.3 return语句,例5-3 根据输入的颜色符号,显示不同的字符串表示的不同颜色。,2023/11/7,北京邮电大学信息与通信工程学院,-38-,2023/11/7,北京邮电大学信息与通信工程学院,-39-,/例5-3 根据输入的颜色符号,显示不同的字符串表示的不同颜色#include using namespace std;void DispColor(char color);void main()char color;coutcolor;DispColor(color);,2023/11/7,北京邮电大学信息与通信工程学院,-40-,/根据输入,显示颜色字符串 void DispColor(char color)switch(color)case r:coutred.;break;case g:coutgreen.;break;case b:coutblue;break;default:break;return;,5.2.3 return语句,例5-4 从输入文件中读入学生人数和每人考试成绩,统计成绩的平均值。,2023/11/7,北京邮电大学信息与通信工程学院,-41-,2023/11/7,北京邮电大学信息与通信工程学院,-42-,/例5-4.从输入文件中读入学生人数和每人考试成绩,统计成绩均值。#include#include using namespace std;int CalMean(char chFileName);/函数原型声明 void main()char chFileName80=;cout chFileName;/输入文件名 int mean=ChlMean(chFileName);/得到平均值 cout平均值=meanendl;,2023/11/7,北京邮电大学信息与通信工程学院,-43-,/计算均值,函数定义如下 int CalMean(char chFileName)int count;/数据个数 int score;/分数 int sum(0),mean;ifstream infile(chFileName);if(!infile)coutscore)/从文件读取成绩,并累计总成绩;cout0)mean=sum/count;/计算平均值 else mean=0;return mean;/将平均值返回主调函数,运行结果:成绩个数:10 成绩:59 39 24 36 87 98 52 67 52 60 平均值=57,5.2.4 函数调用方式,函数语句函数语句形式:函数名(实参数表);TriAreabySide(a,b,c);函数表达式函数调用出现在表达式中,形式:函数名(实际参数表)x=max(a,b);y=sqrt(x);此时函数要使用return语句向主调函数返回一个确定的值,参与它所在的表达式的运算。float max(float a,float b)return a=b?a:b;函数参数函数参数调用方式是将函数调用写在另一次函数调用的实际参数位置。例如:m=max(a,max(b,c);,2023/11/7,北京邮电大学信息与通信工程学院,-44-,5.2.4 函数调用方式,实际参数表可简称为实参表,是按与被调函数形式参数表一一对应的格式组织的参数表,即参数的类型、个数和排列顺序必须与被调函数声明的形式参数表严格一致。实际参数表的各实际参数以逗号间隔,实际参数可以是常量、变量或表达式,变量和表达式必须具有确定值。如果被调函数无形式参数,则实参表也是空的。实际编程中,从可读性考虑,一般使用变量作为实际参数。,2023/11/7,北京邮电大学信息与通信工程学院,-45-,例:计算y=kx+b的函数 float func(int k,int b,float x)return k*x+b;void main()int k,b;float x,y;cinkbx;y=func(k,b,x);,例:找最高分数 int FindMaxValue(int array,int n)int maxValue=array0;for(int k=1;k maxValue)maxValue=arrayk;return maxValue;void main()int score30,num=30;for(int k=0;kscorek;int maxScore=FindMaxScore(score,num);coutmaxScoreendl;,2023/11/7,北京邮电大学信息与通信工程学院,-46-,实际参数以数据值(值传递)或实际存储空间(地址传递)提供了形式参数所需的内容。,#includeusing namespace std;void DisplayMessage();void main()DisplayMessage();/函数调用语句void DisplayMessage()cout只显示确定信息的简单函数不带参数endl;,2023/11/7,北京邮电大学信息与通信工程学院,-47-,如果被调函数无形参,则实参表也是空的。,5.2.4 函数调用方式,5.2.4 函数调用方式,例5-5 编写程序,实现坐标旋转公式:,2023/11/7,北京邮电大学信息与通信工程学院,-48-,2023/11/7,北京邮电大学信息与通信工程学院,-49-,/实现坐标旋转公式#include#include using namespace std;void main()const double PI=3.14;int x,y;/旋转后坐标int x0,y0;/原始坐标int angle;/旋转角度/输入数据coutinput point(x,y):;,cinx0y0;coutangle;/计算旋转后的坐标double theta=angle*PI/180;x=x0*cos(theta)-y0*sin(theta);y=x0*sin(theta)+y0*cos(theta);/输出结果coutx=xendl;couty=yendl;,5.3 函数调用的执行机制和参数传递方式,函数调用过程是如何实现的?程序执行流程能够从主调函数到被调函数,再由被调函数正确返回主调函数的断点继续执行,是基于函数调用工作栈来实现的。函数的参数传递方式值传递地址传递,2023/11/7,北京邮电大学信息与通信工程学院,-50-,5.3.1 函数调用的执行机制,栈是函数调用正确执行的物理基础.栈是一种数据结构,它的工作原理就像在子弹匣压子弹一样,最先压入的子弹要等到最后才飞射出去,而最后压入的子弹则首先飞射出去。,2023/11/7,北京邮电大学信息与通信工程学院,-51-,004010560040105700401058004010590040105A0040106B,A,B,C,D,栈的管理原则:先进后出或 后进先出,5.3.1 函数调用的执行机制,函数调用能够正确执行的物理基础是操作系统在内存中开辟了一块叫做栈的内存空间。断点工作记录断点地址被调函数的形式参数自动局部变量,2023/11/7,北京邮电大学信息与通信工程学院,-52-,5.3.1 函数调用的执行机制,例5-6 从键盘输入屏幕上两点的坐标(x,y),计算两点之间的距离。(分析函数调用时活动记录),2023/11/7,北京邮电大学信息与通信工程学院,-53-,2023/11/7,北京邮电大学信息与通信工程学院,-54-,void main()int x1,y1,x2,y2;/两点坐标float dist;/两点间距离coutx1y1;coutx2y2;dist=CalDistance(x1,y1,x2,y2);coutdistance between point(x1,y1)and point(x2,y2):distendl;,栈,仅一个工作记录,活动工作记录,2023/11/7,北京邮电大学信息与通信工程学院,-55-,/计算距离float CalDistance(int xx1,int yy1,int xx2,int yy2)int dx,dy;dx=xx2-xx1;dy=yy2-yy1;float dist=sqrt(dx*dx+dy*dy);return dist;,栈,工作记录示意,工作记录,活动工作记录,5.3.2 函数的参数传递方式,函数之间的信息交换的一种重要形式是函数的参数传递,由函数的形式参数和实际参数实现。函数在没有被调用时,函数的形式参数并不占有实际的内存空间,也没有实际的值。C+语言中函数的参数传递方式分为两种:值传递地址传递,2023/11/7,北京邮电大学信息与通信工程学院,-56-,2023/11/7,北京邮电大学信息与通信工程学院,-57-,值传递,如果函数的形式参数为普通变量,当函数被调用时,系统为这些形式参数分配内存空间,并用实际参数值初始化对应的形式参数,形式上实际参数的值传递给了形式参数。这就是函数调用时参数的值传递。,值传递方式,实际参数和形式参数各自占有自己的内存空间;参数传递方向只能由实际参数到形式参数;不论函数对形式参数作任何修改,对相应的实际参数都没有影响。,5.3.2 函数的参数传递方式,5.3.2 函数的参数传递方式,例5-7 从键盘输入两整数,交换次序后输出。,2023/11/7,北京邮电大学信息与通信工程学院,-58-,2023/11/7,北京邮电大学信息与通信工程学院,-59-,/演示函数参数值传递单向性的例程#includevoid swap(int a,int b);int main()int x(5),y(10);coutx=x y=yendl;swap(x,y);coutx=x y=yendl;return 0;,5,10,x,y,1024,1028,运行结果:x=5 y=10 x=5 y=10,2023/11/7,北京邮电大学信息与通信工程学院,-60-,void swap(int a,int b)int t;t=a;a=b;b=t;,5,a,2048,10,b,2052,t,2056,5,10,5,编程技巧:交换两个变量的值,需要引入第三个变量缓存数据。,例,如果一个数的所有真因子(包括1,但不包括这个数本身)之和正好等于这个数本身,则称此数为完美数。例如:6=123,而 1+2+3=6;28=147=1214,而 1+2+4+7+14=28。如何确定完美数,欧几里得发现,只要是一个素数,则 一定是一个完美数。编写程序找出最小的5个完美数。,2023/11/7,北京邮电大学信息与通信工程学院,-61-,体会函数参数的值传递,2023/11/7,北京邮电大学信息与通信工程学院,-62-,/寻找最小的五个完美数#include#includeusing namespace std;bool DecidePrime(unsigned int number);unsigned int power(unsigned int x,unsigned int y);void main()unsigned int perfect_number;unsigned int num,temp;short n(2);short counter(0);/计数器,2023/11/7,北京邮电大学信息与通信工程学院,-63-,while(counter5)temp=power(2,n);num=temp-1;if(DecidePrime(num)perfect_number=temp/2*num;coutn=n,perfect number=perfect_numberendl;counter+;n+;,2023/11/7,北京邮电大学信息与通信工程学院,-64-,/计算指数unsigned int power(unsigned int x,unsigned int y)unsigned int mul(1);for(int i=1;i=y;i+)mul*=x;return mul;,2023/11/7,北京邮电大学信息与通信工程学院,-65-,/判别素数bool DecidePrime(unsigned int number)unsigned int i,k;k=sqrt(number);for(i=2;i=k+1)/判断number是否被小于number的数整除 return true;else return false;,5.3.2 函数的参数传递方式,地址传递地址变量做形参数组名指针变量引用,2023/11/7,北京邮电大学信息与通信工程学院,-66-,5.3.2 函数的参数传递方式,冒泡排序 int array5=5,4,3,2,1;,2023/11/7,北京邮电大学信息与通信工程学院,-67-,5.3.2 函数的参数传递方式,例5-9 用整型数组存储数据,编写冒泡排序函数BubbleSort(),在主调函数中用随机数产生函数生成数组元素,并输出排序的结果。,2023/11/7,北京邮电大学信息与通信工程学院,-68-,2023/11/7,北京邮电大学信息与通信工程学院,-69-,/例5-9 基于数组的冒泡排序例#include#include using namespace std;void BubbleSort(int array,int n);/函数原型声明,2023/11/7,北京邮电大学信息与通信工程学院,-70-,void main()const int N=20;int arrayN=0;srand(unsigned int)time(NULL);int k;cout待排序数据:endl;for(k=0;kN;k+)/数据生成 arrayk=rand()%100;cout arrayk,;BubbleSort(array,N);/调用排序函数 cout endl排序后数据:endl;for(k=0;kN;k+)/数据生成 cout arrayk,;coutendl;,2023/11/7,北京邮电大学信息与通信工程学院,-71-,/冒泡排序 void BubbleSort(int a,int n)int temp;for(int pass=1;passak+1)temp=ak;ak=ak+1;ak+1=temp;,运行结果:待排序数据:37,99,56,87,48,96,71,88,63,44,34,21,59,0,36,92,53,25,4,20 排序后数据:0,4,20,21,25,34,36,37,44,48,53,56,59,63,71,87,88,92,96,99,注意,(1)数组名作为形式参数,只将数组的起始地址传递给了被调函数,数组的大小需要单独通过值传递的方式传给被调函数。例5-9中的用法是一维数组名形式参数,只传一个大小即可;如果是多维数组名作为函数的形式参数,则数组的每一维的大小都需要传给被调函数。例如,定义求一个矩阵的转置矩阵的函数TransposeMatrix(),矩阵用二维数组表示,函数接口如下:void TransposeMatrix(int matrixN,int tMatrixM,int rows,int cols);,2023/11/7,北京邮电大学信息与通信工程学院,-72-,注意,(2)多维数组名作为形式参数,只可以省略第一维(最左边)的大小,也可以不省略。在被调函数中访问这个形式上的数组时,切忌下标越界问题。,2023/11/7,北京邮电大学信息与通信工程学院,-73-,5.4 递归函数和递归调用,递归函数是函数的一种特殊形式,适合实现数学上的一些递归问题。使用递归函数可以简单明了地表达算法(算法的可读性好),但算法的效率一般不高。,2023/11/7,北京邮电大学信息与通信工程学院,-74-,5.4.1 嵌套调用,C+的函数不能嵌套定义 C+的函数可以嵌套调用,2023/11/7,北京邮电大学信息与通信工程学院,-75-,不能嵌套定义void main()int x,y;int sub(int a,int b)int c=a+b;,可以嵌套调用main()DecidePrime()sqrt()if(DecidePrime(num)k=sqrt(number);,5.4.2 递归函数和递归调用,递归函数是函数体内有调用函数自己的语句或通过其它函数间接调用函数自己的函数。递归调用是调用递归函数而形成的一种函数调用方式。递归函数用于实现数学中的递归问题比较直观方便。,2023/11/7,北京邮电大学信息与通信工程学院,-76-,经典递归调用问题,阶乘定义式:,2023/11/7,北京邮电大学信息与通信工程学院,-77-,2023/11/7,北京邮电大学信息与通信工程学院,-78-,#include using namespace std;int factorial(int n);void main()coutn;n_fact=factorial(n);coutthe factorial of nis:n_factendl;,返回地址1,2023/11/7,北京邮电大学信息与通信工程学院,-79-,int factorial(int n)int fn;if(n=0)fn=1;else fn=n*factorial(n-1);return fn;,返回地址2,栈状态,断点地址,参数,局部变量,top,top,top,top,实例演示,2023/11/7,北京邮电大学信息与通信工程学院,-80-,int factorial(int n)int fn;if(n=0)fn=1;else fn=n*factorial(n-1);return fn;,返回地址2,栈状态,top,top,top,top,递归问题的求解实际分成两个阶段:化简问题的递推阶段;达到递归终止条件得到基本情况的结果,并逐步回推结果阶段。递归函数的主要两部分 具有更简单参数的递归调用 停止递归的终止条件(递归终止条件),2023/11/7,北京邮电大学信息与通信工程学院,-81-,例5-11,整数x和y的最大公约数是x和y能够整除的最大整数。编写一个递归函数GcommonDivisor,返回整数x和y的最大公约数。算法:整数x和y的最大公约数的递归实现:如果y等于0,则GcommonDivisor(x,y)为x;否则GcommonDivisor(x,y)为GcommonDivisor(y,x%y).其中%是求余运算符。,2023/11/7,北京邮电大学信息与通信工程学院,-82-,理解递归问题,2023/11/7,北京邮电大学信息与通信工程学院,-83-,/计算x和y的最大公约数(递归函数)#includeusing namespace std;int GcommonDivisor(int x,int y);void main()int x,y;coutxy;coutthe greatest common divisor of xand y:GcommonDivisor(x,y)endl;,地址1,2023/11/7,北京邮电大学信息与通信工程学院,-84-,int GcommonDivisor(int x,int y)int gcd;if(y=0)gcd=x;elsegcd=GcommonDivisor(y,x%y);return gcd;,以输入10,8为例,地址2,问题:用循环能实现吗?(作业),5.5 内 联 函 数,函数调用时,系统首先要保存主调函数的相关信息,再将控制转入被调函数,这些操作增加了程序执行的时间开销。C+提供的内联函数形式可以减少函数调用的额外开销(时间空间开销),特别是一些常用的短小的函数适合采用内联函数形式。,2023/11/7,北京邮电大学信息与通信工程学院,-85-,5.5 内 联 函 数,内联函数的定义形式:inline 函数类型 函数名(形式参数表)函数体,2023/11/7,北京邮电大学信息与通信工程学院,-86-,5.5 内 联 函 数,例5-13 使用内联函数求三个整数中的最大值。,2023/11/7,北京邮电大学信息与通信工程学院,-87-,2023/11/7,北京邮电大学信息与通信工程学院,-88-,/内联函数例#includeusing namespace std;inline int max(int x,int y,int z)return(x=y)?(x=z?x:z):(y=z?y:z);,void main()int a,b,c;coutabc;coutMaximum is max(a,b,c)endl;,(a=b)?(a=c?a:c):(b=c?b:c),2023/11/7,北京邮电大学信息与通信工程学院,-89-,内联函数之所以能够减少函数调用时的系统空间和时间开销,是因为系统在编译程序时就已经把内联函数的函数体代码插入到相应的函数调用位置,成为主调函数内的一段代码,可以直接执行,不必再转换流程控制权。这样的结构,自然节省了时间和空间开销,但使得主调函