函数和编译预处理讲稿.ppt
《函数和编译预处理讲稿.ppt》由会员分享,可在线阅读,更多相关《函数和编译预处理讲稿.ppt(97页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、关于函数和编译预处理第一页,讲稿共九十七页哦3.1 概述概述函数:functionfunction,功能。功能。执行或承担某一功能的执行或承担某一功能的程序段程序段,解答某问题的,解答某问题的一段程序一段程序。它有特定的它有特定的组织格式组织格式和和使用方式使用方式。函数 与 程序的关系:一个复杂的C语言程序包含多个函数。(主函数main)它们可存放在多个文件中。模块化程序设计思想:划分程序功能,每个子功能用子函数(主函数之外的函数)来承担,而让 主函数 去 调用(使用)这些子函数 从而实现程序的所有功能。每个函数单独设计调试,而且可以重复使用。第二页,讲稿共九十七页哦main()func1(
2、)func2()func3()func5()func4()主调函数主调函数、调用、调用被调函数(子函数)、被调用参数返回值主调函数主调函数 和和 被调函数 的关系:上下级 关系请问:main()被 谁调用?一个程序中 函数 调用 的示意图:第三页,讲稿共九十七页哦#include void main()int n;cinn;if(n1)cout“the sum is:”sum(n)endl;/调用调用 sum()函数函数 int sum(int n)例3.1 编写函数求前 n 个自然数之和,n 的值从键盘输入。函数首部、函数头函数首部/函数头函数体 int k,s=0;for(k=1;ky)?
3、x:y;return z;void main(void)int a,b,c;cinab;c=max(a,b);cout“The max is”cy)?x:y;return z;void main(void)int a,b,c;cinab;c=max(a,b);cout“The max is”cendl;ab23调用处(表达式中)调用处(表达式中)3xy23zc=3不要将函数名做变量用!不能写成 max=z;第十四页,讲稿共九十七页哦(2)自定义函数的声明函数类型关键字 函数名(参数1 类型,参数1名称 ,参数2 类型,参数2名称 );什么时候需要声明?声明的含义、作用?声明的格式、位置?(1)
4、库函数的声明 对库函数的声明已经写在有关 包含文件(头文件)中了,因此只要在程序文件首部用 include 指令将这些 包含文件 包含到本程序中来,就完成了对库函数的声明。#include 3.2.2 函数的声明(补述)函数的声明形式也叫做函数原型(function prototype)。它说明了函数的类型、函数名、函数各形式参数类型。函数类型关键字 函数名(参数1 类型 ,参数2 类型 );修改p68名称任意,可省略第十五页,讲稿共九十七页哦【例例3.2】输入输入圆柱体圆柱体的底面半径和高,求底面的底面半径和高,求底面圆圆面积面积和和体积体积。设函数设函数 area()和和 volum()分
5、别求分别求圆圆面积和圆柱体体积。面积和圆柱体体积。#include using namespace std;void main()double volum(float,float);/声明声明 double area(float r);/声明声明 float r,h;double s,v;coutrh;s=area(r);/调用调用 v=volum(r,h);/调用调用 couts=s,v=vab;c=add(a,3.5);cout“The sum is”cendl;(2)实参 与 形参的类型应相同或赋值兼容。第十八页,讲稿共九十七页哦 值传递:调用函数时,计算机将函数调用处的实参值传给被调函
6、数的形参,在被调函数执行过程中,形参可以被改变,但不影响函数调用处的实参值。换一句话说,这种参数传递机制是单向影响。3.3.1 参数的 值传递(前面已介绍)第十九页,讲稿共九十七页哦 除了3.3.2小节介绍的值传递参数方式外,函数调用还有一种特殊的值传递形式,即传递的值不是一般的数值,而是一些内存单元地址编号(即地址),这时,一般称之为参数的地址传递。在这种参数传递形式中,无论在函数的定义中出现的形参还是在调用语句中出现的实参,都是代表一些内存单元地址编号(即地址数值),而不是一般的数值。C+中的参数地址传递情况一般有如下几种:实参可以是一个有确定值的普通变量的地址,或者是一个已经初始化的指针
7、变量;或者是一个初始化的数组名;或者是一个具体的函数名。而形参可以是一个任意普通变量的地址,或是一个任意指针变量,或是一个任意的数组名,或是一个指向函数的指针变量(对应于实参是具体函数名)。3.3.2 参数的 地址传递(4章)第二十页,讲稿共九十七页哦 实际上,这种参数传递机制就是在函数调用时把一个内存单元地址传递给形参,使形参也具有实参的内存单元地址(即两者对应同一个内存单元),称作形参和实参地址结合,两者合二为一。这样一来,任何时候形参的值等于实参的值;而实参的值也等于形参的值。因此,形参在函数中发生变化后,也会引起实参跟着变化(因为它们是捆绑在一起的,一体化的)。这就意味着按地址传递的方
8、式,在调用刚开始时实参的值影响了形参;而在被调函数执行过程中形参值若发生了变化,它也会影响实参的值变化。即机制是双向影响,这与普通值传递方式的单向影响机制形成对比。第二十一页,讲稿共九十七页哦【例例3.5】延迟函数的使用。延迟函数的使用。#include void delay(int loop);/声明声明void main()coutbeginendl;delay(1000);/调用调用 coutendendl;void delay(int loop)/定义定义 if(loop=0)return;for(int i=0;iloop;i+)coutiendl;3.3.3 带 默认值 的参数(C
9、+)C+语言中,允许在语言中,允许在函数定义函数定义或或声明声明时给一个或多个形参指定时给一个或多个形参指定默认值默认值。这样,后面的。这样,后面的函数调用函数调用中,可以不给具有中,可以不给具有默认值默认值的形参设的形参设定相应的实参。定相应的实参。void delay(int loop=1000);void delay(int x=1000);delay();/调用调用 第二十二页,讲稿共九十七页哦 对于教材【例3.2】的求圆柱体体积的函数volume(),如下声明:float volume(float r,float h=8.5);/只对形参h指定默认值8.5这时函数调用形式:volum
10、e(6.0);/相当于volume(6.0,8.5)volume(6.0,7.2);/r的值为6.0,h的值为7.2 如果函数有多个形参,可以对每个或部分形参指定默认值。指定默认值的形参必须放在参数列表中的 最 右 边。第二十三页,讲稿共九十七页哦课堂总结第二十四页,讲稿共九十七页哦a 函数函数b 函数函数main 函数函数结束结束(2)(3)(4)(5)(6)(7)(8)(9)C C语语言言不允许不允许对函数作对函数作嵌套定义!嵌套定义!3.4.1 3.4.1 嵌套调用:嵌套调用:在一个在一个函数定义函数定义中,可以中,可以调用调用另一个函数另一个函数。程序执行时,在调用一个函数的过程中,又
11、调用程序执行时,在调用一个函数的过程中,又调用另一个函数另一个函数。例如例如:3.4 函数的 嵌套调用 和 递归调用调用调用 a 函数函数调用调用 b 函数函数main()函数函数 直接地 调用了 a a函数函数,main()函数函数 嵌套地 调用了 b b函数函数(间接调用间接调用)。第二十五页,讲稿共九十七页哦long comb(int n,int m)/定义组合函数long c;c=fac(m)/(fac(n)*fac(m-n);/嵌套调用阶乘函数 return c;void main()int n,m;long c;coutplease input two integer number
12、s:m,nmn;c=comb(n,m);/调用组合函数combcoutc=cendl;main()分析:定义函数long comb(int n,int m)求组合数。定义函数long fac(int k)求k的阶乘。comb()fac()#include using namespace std;long fac(int k)/定义求阶乘的函数long f=1;int i;for(i=1;i=k;i+)f=f*i;return f;【例3.6】编程求组合数,第二十六页,讲稿共九十七页哦3.4.2 函数的 递归调用 在调用一个函数的过程中,被调用函数又直接或间接地调用 自身,这种调用过程称为函数的
13、递归(recursive)调用。直接递归 调用 函数 的代码形式:int f()/函数f1的定义 /函数其它部分 z=f();/直接调用自身 /函数其它部分 在函数f()中,又直接调用了f()函数。第二十七页,讲稿共九十七页哦间接递归 调用 函数 可以表现为如下:int f1()/函数f1的定义 /f1的其他部分x=f2();/调用f2()/f1的其他部分 int f2()/函数f2的定义 /f2的其他部分y=f1();/调用f1()/f2的其他部分 第二十八页,讲稿共九十七页哦函数的直接递归调用 函数的间接递归调用 图中调用过程特点:这两种递归调用都是无终止的自身调用?!程序中不应出现这种无
14、终止的递归调用,而只应出现有限次数的、有终止的递归调用!解决:用if语句来控制,只有在某一条件成立时才继续执行递归调用,否则就不再继续。包含递归调用的函数称为递归函数。第二十九页,讲稿共九十七页哦v【例3.7】用递归计算 n!。求n!,应先求(n-1)!;而求(n-1)!,又需要先求(n-2)!,而求(n 2)!;又可以变成求(n-3)!,如此继续,直到最后变成求1!的问题,而根据公式有1!=1(这就是本问题的递归终止条件)。由终止条件得到1!结果后,再反过来 依次求出2!,3!直到最后求出n!。第三十页,讲稿共九十七页哦v【例3.7】用递归计算n!。n!本身就是以递归的形式定义的:#incl
15、ude using namespace std;long fac(int n)long f;if(n=1)f=1;else f=n*fac(n-1);/递归调用,求(n-1)!return f;void main()long y;int n;coutplease input a integer n n;y=fac(n);/调用fac(n)求n!coutn=n,y=y1)long fibonacci(int n)if(n=0|n=1)return n;elsereturn fibonacci(n-1)+fibonacci(n-2);程序如下所示:程序如下所示:实验教程实验教程P19 三三 实验思
16、考实验思考 1:求求Fibonacci数列数列 大于大于t的最小项的最小项 的值。的值。第三十四页,讲稿共九十七页哦void main()int n=0,t;long result,t;cint;result=fibonacci(n);whlie(result=t)n+;result=fibonacci(n);coutresult;方法:1.递归函数实验教程:实验教程:P19 三三 实验思考实验思考 1 2.用循环做 实验教程:实验教程:p90.四四,1 3.数组 教材:教材:p140,3第三十五页,讲稿共九十七页哦求两个数最大公约数的方法最大公约数的方法1.辗转相除法辗转相除法 (p57)2
17、.短除法短除法3.试探法试探法4.递归方法递归方法 (用(用 函数递归调用函数递归调用 做)做)用 g(m,n)表示m、n的最大公约数最大公约数,请写出则其递归定义。请写出则其递归定义。第三十六页,讲稿共九十七页哦递归边界(终止)条件递归边界(终止)条件使问题向递归边界(终止)条件转化的规则使问题向递归边界(终止)条件转化的规则类似例题类似例题习题:习题:强调:上述问题的递归定义强调:上述问题的递归定义具备两个成分:具备两个成分:第三十七页,讲稿共九十七页哦递推方法递推方法程序描述繁杂,可读性差;程序描述繁杂,可读性差;主要采用主要采用 循环结构;循环结构;逐步执行;逐步执行;当前值的求得总建
18、立在前面求解的基础上;当前值的求得总建立在前面求解的基础上;递归方法递归方法描述与原始问题(递归公式)比较接近;描述与原始问题(递归公式)比较接近;书写简洁、易读易写;书写简洁、易读易写;易于分析算法的复杂性和证明算法的正确性;易于分析算法的复杂性和证明算法的正确性;在问题转化时,需要花时间和存储空间将有关的在问题转化时,需要花时间和存储空间将有关的“现场信息现场信息”保存起来;当达到终止条件时,系保存起来;当达到终止条件时,系统又需要花时间将有关的统又需要花时间将有关的“现场信息现场信息”恢复以便恢复以便处理未曾处理完的函数调用处理未曾处理完的函数调用。占用存储空间少,执行速度快。占用存储空
19、间少,执行速度快。递归递归 与与 递推递推 算法算法递归函数的适应场合:待求解的问题含有递归关系。第三十八页,讲稿共九十七页哦【例3.8】汉诺塔问题abc汉诺塔(Tower of Hanoi)问题据说来源于布拉玛神庙。该问题的装置如图3.6所示(图上仅画三个金片以简化问题的原理,原问题有64个金片),底座上有三根金钢石的针,第一根针a上放着从大到小64个金片。解决该问题就是要想法把所有金片从第一根针a上移到第三根针c上,第二根针b作为中间过渡。要求是每次只能移动一个金片,并且任何时候不允许大的金片压在小的金片上面。图3.6 三个金片的汉诺塔问题装置第三十九页,讲稿共九十七页哦1.本问题的递归终
20、止条件。如果只有1个盘,显然问题的解就很明显是:直接把金片从a移到c。因此终止条件是n=1;终止条件对应的操作是直接把金片从a移到c,示意ac。2.本问题的递归分析:移动n个金片从a到c,必须先将n-1个金片从a借助c移动到b,移动n-1个金片与原问题相同,但规模变小,即向终止条件接近,因此,此问题可以用递归过程完成。递归过程可以用如下步骤表示:(1)将n-1个金片从a经过c移动到b。(2)将第n个金片从a直接移动到c。(3)再将n-1个金片从b经过a移动到c。第四十页,讲稿共九十七页哦一般地,设将n个金片从x针借助y针移动到z针的函数原形为:void hanoi(int n,char x,c
21、har y,char z)根据解题步骤,可以写出求解n个金片的汉诺塔函数如下:#include /*ex3_8.cpp*using namespace std;void hanoi(int n,char x,char y,char z)if(n=1)/n=1时,直接将金片从x移动到z cout x z 1时 hanoi(n-1,x,z,y);/先将n-1个金片从借助z移动到y cout x z 1时,就递归调用hanoi(),每次n减1。最后当n=1时,直接移动该金片就可以了。主函数如下:void main()int n;cout input n:n;hanoi(n,a,b,c);/n个金片从
22、a针借助b针移动到c针 虽然递归调用在写程序时很简单,但执行起来却很复杂(时间、存储空间都开销大)。对于汉诺塔问题程序的执行过程分析比较复杂,有兴趣的读者可参阅教材对3个盘情景的分析(图3.7 及其相应文字叙述)。第四十二页,讲稿共九十七页哦3.5 内置函数(C+,选讲)一般函数调用的过程:调用前:参数传递,保存下条指令地址信息,和CPU状态信息,执行流程转入被调函数。调用完毕:传回函数值,执行流程回到主调函数。函数调用花费额外的时间和空间!如果函数频繁地被调用,如调用出现在循环中,则开销大,影响效率(缺点)。函数的优点之一:便于实现模块化/结构化程序设计的方法。发挥其优点,克服其缺点,采用内
23、置函数第四十三页,讲稿共九十七页哦3.5 内置函数(C+,选讲)一般函数调用的过程:C+编译时将被调函数的代码直接嵌入到主调函数中,程序执行时不必将流程转出去。这种嵌入到主调函数中的函数称为内置函数(inline function),又称内嵌函数 或 内联函数。第四十四页,讲稿共九十七页哦3.5.1 内置函数的作用 提高程序中函数调用的效率;并保持程序的可读性。适应场合:如果函数频繁地被调用.指定内置函数的方法:在函数定义首行(或函数说明)的左端加一个关键字inline即可。第四十五页,讲稿共九十七页哦#include int is_number(char);/函数声明void main()c
24、har c;while(c=cin.get()!=n)if(is_number(c)/调用一个小函数coutyou enter a digit n;else cout=0&ch=9)?1:0;【例3.9】判断用户从键盘输入的系列字符是数字字符还是其它字符的函数is_number()。第四十六页,讲稿共九十七页哦程序中不断到设备中读取数据,频繁调用程序中不断到设备中读取数据,频繁调用is_number()函数。为了避函数。为了避免频繁调用函数,提高执行效率,可以将免频繁调用函数,提高执行效率,可以将【例例3.9】程序改为:程序改为:#include /*ex3_9b.cpp*void main(
25、)char c;while(c=cin.get()!=n)if(c=0&c=9)?1:0)/修改处:直接计算表达式修改处:直接计算表达式 coutyou enter a digit n;else coutyou enter a non-digit n;第四十七页,讲稿共九十七页哦修改后的程序在if语句中用表达式替换了函数调用。在程序运行上,提高了一些执行效率,因为免去了大量的函数调用开销。但是,由于is_number函数比相应的表达式可读性好,所以修改后的代码可读性降低,尤其若程序中多处出现is_number的替换时,会大大降低可读性。我们希望既要用函数调用来体现其结构化和可读性,又要使效率尽
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 函数 编译 预处理 讲稿
限制150内