1 / 102

第三章 函数

第三章 函数. 时间安排:4学时 3.1节2学时、其余6节2学时 教学目标:掌握函数的定义与调用方法 教学重点:函数定义、声明及调用方法 教学难点:递推、递归、复合函数设计要领. C++ 语言程序设计. 本章主要内容. 函数的定义和调用 函数间的参数传递 内联函数 带默认形参值的函数 函数重载 C++ 系统函数 深度探索. 2. 函数的定义. 函数是面向对象程序设计中,对功能的抽象 函数定义的语法形式 类型标识符 函数名(形式参数表) { 语句序列 }. 函数的声明与使用.

shaina
Download Presentation

第三章 函数

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第三章 函数 时间安排:4学时 3.1节2学时、其余6节2学时 教学目标:掌握函数的定义与调用方法 教学重点:函数定义、声明及调用方法 教学难点:递推、递归、复合函数设计要领 C++语言程序设计

  2. 本章主要内容 函数的定义和调用 函数间的参数传递 内联函数 带默认形参值的函数 函数重载 C++系统函数 深度探索 2

  3. 函数的定义 函数是面向对象程序设计中,对功能的抽象 函数定义的语法形式 类型标识符 函数名(形式参数表) { 语句序列 } 函数的声明与使用 是被初始化的内部变量,寿命和可见性仅限于函数内部 若无返回值,写void 3

  4. 函数的定义 形式参数表 <type1> name1, <type2> name2, ..., <typen> namen 函数的返回值 由 return 语句给出,例如:return 0; 无返回值的函数(void类型),不必写return语句。 函数的声明与使用 4

  5. 函数的调用 调用前先声明函数: 若函数定义在调用点之前,则无需另外声明; 若函数定义在调用点之后,则需要在调用函数前按如下形式声明函数原型: 类型标识符 被调用函数名(含类型说明的形参表); 调用形式 函数名(实参列表) 嵌套调用 函数可以嵌套调用,但不允许嵌套定义。 递归调用 函数直接或间接调用自身。 函数的声明与使用 5

  6. 例3-1编写一个求x的n次方的函数 #include <iostream> using namespace std; //计算x的n次方 doublepower(double x, int n) { double val =1.0; while(n--)val *= x; return val; } int main() { cout << "5 to the power 2 is " << power(5,2) << endl; system("pause");return 0; } 函数的声明与使用 6

  7. 运行结果: 5to the power 2 is 25 例3-1编写一个求x的n次方的函数 函数的声明与使用 7

  8. 例3-2 数制转换 题目: 输入一个8位二进制数,将其转换为十进制数输出。 例如:11012=1(23)+1(22)+0(21)+1(20)=1310 所以,如果输入1101,则应输出13 函数的声明与使用 8

  9. #include <iostream> using namespace std; //计算x的n次方 double power (double x, int n); int main() { int value = 0; cout << "Enter an 8 bit binary number "; for (int i = 7; i >= 0; i--) { char ch; cin >> ch; if (ch == '1') value += static_cast<int>(power(2, i)); } cout << "Decimal value is " << value << endl; return 0; } double power (double x, int n) { double val = 1.0; while(n--)val *= x; return val; } 运行结果: Enter an 8 bit binary number 01101001 Decimal value is 105 9

  10. 例3-3编写程序求π的值 其中arctan用如下形式的级数计算: 直到级数某项绝对值不大于10-15为止;π和x均为double型。 函数的声明与使用 10

  11. #include <iostream> using namespace std; double arctan(double x) { double sqr = x * x; double e = x; double r = 0; int i = 1; while (e / i > 1e-15) { double f = e / i; r = (i % 4 == 1) ? r + f : r - f; e = e * sqr; i += 2; } return r; } 11

  12. int main() { double a = 16.0 * arctan(1 / 5.0); double b = 4.0 * arctan(1 / 239.0); //注意:因为整数相除结果取整,如果参数写1/5,1/239,结果就都是0 cout << "PI = " << a - b << endl; return 0; } 运行结果: PI=3.14159 12

  13. 例3-4 寻找并输出11~999之间的数m,它满足m、m2和m3均为回文数。 回文:各位数字左右对称的整数。 例如:11满足上述条件112=121,113=1331。 分析: 10取余的方法,从最低位开始,依次取出该数的各位数字。按反序重新构成新的数,比较与原数是否相等,若相等,则原数为回文。 函数的声明与使用 13

  14. #include <iostream> using namespace std; //判断n是否为回文数 bool symm(unsigned n) { unsigned i = n; unsigned m = 0; while (i > 0) { m = m * 10 + i % 10; i /= 10; } return m == n; } 14

  15. int main() { for(unsigned m = 11; m < 1000; m++) if (symm(m) && symm(m * m) && symm(m * m * m)) { cout << "m = " << m; cout << " m * m = " << m * m; cout << " m * m * m = " << m * m * m << endl; } return 0; } 15

  16. 运行结果: m=11 m*m=121 m*m*m=1331 m=101 m*m=10201 m*m*m=1030301 m=111 m*m=12321 m*m*m=1367631 16

  17. 例3-5 计算如下公式,并输出结果: 其中r、s的值由键盘输入。sin x的近似值按如下公式计算,计算精度为10-6: 函数的声明与使用 17

  18. #include <iostream> #include <cmath> //对C++标准库中数学函数的说明 using namespace std; const double TINY_VALUE = 1e-10; double tsin(double x) { double g = 0; double t = x; int n = 1; do { g += t; n++; t = -t * x * x / (2 * n - 1) / (2 * n - 2); } while (fabs(t) >= TINY_VALUE); return g; }  18

  19. int main() { double k, r, s; cout << "r = "; cin >> r; cout << "s = "; cin >> s; if (r * r <= s * s) k = sqrt(tsin(r) * tsin(r) + tsin(s) * tsin(s)); else k = tsin(r * s) / 2; cout << k << endl; return 0; } 运行结果: r=5 s=8 1.37781 19

  20. 例3-6投骰子的随机游戏 每个骰子有六面,点数分别为1、2、3、4、5、6。游戏者在程序开始时输入一个无符号整数,作为产生随机数的种子。 每轮投两次骰子,第一轮如果和数为7或11则为胜,游戏结束;和数为2、3或12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮、第三轮...直到某轮的和数等于点数则取胜,若在此前出现和数为7则为负。 由rolldice函数负责模拟投骰子、计算和数并输出和数。 函数的声明与使用 20

  21. rand 函数原型:int rand(void); 所需头文件:<cstdlib> 功能和返回值:求出并返回一个伪随机数 srand 函数原型:void srand(unsigned int seed); 参数:seed产生随机数的种子。 所需头文件:<cstdlib> 功能:为使rand()产生一序列伪随机整数而设置起始点。使用1作为seed参数,可以重新初化rand()。 21

  22. #include <iostream> #include <cstdlib> using namespace std; //投骰子、计算和数、输出和数 int rollDice() { int die1 = 1 + rand() % 6; int die2 = 1 + rand() % 6; int sum = die1 + die2; cout << "player rolled " << die1 << " + " << die2 << " = " << sum << endl; return sum; } 22

  23. enum GameStatus { WIN, LOSE, PLAYING }; int main() { int sum, myPoint; GameStatus status; unsigned seed; cout << "Please enter an unsigned integer: "; cin >> seed;//输入随机数种子 srand(seed);//将种子传递给rand() sum = rollDice(); //第一轮投骰子、计算和数 23

  24. switch (sum) { case 7: //如果和数为7或11则为胜,状态为WIN case 11: status = WIN; break; case 2: //和数为2、3或12则为负,状态为LOSE case 3: case 12: status = LOSE; break; default: //其它情况,游戏尚无结果,状态为PLAYING,记下点数,为下一轮做准备 status = PLAYING; myPoint = sum; cout << "point is " << myPoint << endl; break; } 24

  25. while (status == PLAYING) { //只要状态仍为PLAYING,就继续进行下一轮 sum = rollDice(); if (sum == myPoint) //某轮的和数等于点数则取胜 status = WIN; else if (sum == 7) //出现和数为7则为负 status = LOSE; } //当状态不为PLAYING时上面的循环结束,以下程序段输出游戏结果 if (status == WIN) cout << "player wins" << endl; else cout << "player loses" << endl; return 0; } 25

  26. 运行结果2: Please enter an unsigned integer:23 player rolled 6 + 3 = 9 point is 9 player rolled 5 + 4 = 9 player wins 26

  27. 嵌套调用 函数的声明与使用 main{} 调fun1() 结束 fun1() 调fun2() 返回 fun2() 返回 ② ③ ④ ① ⑤ ⑨ ⑦ ⑧ ⑥ 27

  28. 例3-6 输入两个整数,求平方和。 #include <iostream> using namespace std; int fun2(int m) { return m * m; } int fun1(int x,int y) { return fun2(x) + fun2(y); } 函数的声明与使用 28

  29. int main() { int a, b; cout << "Please enter two integers (a and b): "; cin >> a >> b; cout << "The sum of square of a andb: " << fun1(a, b) << endl; return 0; } 运行结果: Please enter two integers(a and b): 3 4 The sum of square of a and b: 25 29

  30. 小结与作业 • C++中的函数与数学所讲的函数有联系,但有区别: • 相同点:命名、自变量、函数值(返回值)、复合函数 • 区别:函数值可以是void(空),一个函数完成一项任 • 务,主要用于模块化设计 • C++函数按调用区分为:被调函数(下级)、主调函数(上级) • 函数之间的信息传递主要靠函数值、参数,前者下级向上级传,后者上级向下级传(特殊情况,可以回传) • 应坚持先定义后使用的原则,若要使用后面定义的函数,可以使用声明的方法。 作业:P96:3-1~3-10

  31. 第三章 函数 时间安排:4学时 3.1节2学时、其余6节2学时 教学目标:掌握函数的定义与调用方法 教学重点:函数定义、声明及调用方法 教学难点:递推、递归、复合函数设计要领 C++语言程序设计

  32. 本节主要内容 递推函数 递归函数 函数间的参数传递 内联函数 带默认形参值的函数 函数重载 C++系统函数 32

  33. 递推算法是由简单问题开始,使用归纳推理的思想,逐步递推,最终得到问题的解。 使用递推算法解决问题,首先要分析问题,从中得到一个递推公式,递推公式是用已知项描述未知项的公式,它有一个适用范围,有一个递推初值。如用sn表示从1到n的累加和,则显然有: s1=1 s2=s1+2 s3=s2+3 ......... si=si-1+i 最后的si=si-1+i 称为递推公式,适用范围为i=2、3、...、n s1=1称为递推初值。 递推函数(补充内容)

  34. 对前述的递推增加一个递推初值 s0=0,则s1=1变为 s1=s0+1 s2=s1+2 s3=s2+3 ......... si=si-1+i 最后的递推公式si=si-1+i 的适用范围为i=1、2、3、...、n 使用递推公式,注意公式的适用范围,同时注意递推初始值,可以十分方便的编写出递推程序。 递推函数(补充内容)

  35. 对前述的求从1到n求和的问题编写函数如下: int sum(int n) { int s=0; for(int i=1;i<=n;i++) s=s+i; return s; } 递推函数(补充内容)

  36. 递推函数(补充内容) • 模仿从求从1到n的和的递推函数的编写方法,挑学生写出以下问题的递推公式,并注明初值、适用范围: • 1、求p=n! • 2、求pow=mn • 3、求斐波那契数列

  37. 递归是函数直接或间接调用自身的一种函数调用方式。 递归算法是由复杂问题开始,将其转化为一个与其相似的但规模小的问题的组合,逐步进行,最终转化为可直接求解的具体问题。 使用递归算法解决问题,首先要分析问题,从中得到一个递归公式,递归公式是用较小规模的问题描述现有规模的问题,它有一个描述问题规模的参数,每次递归调用,这个参数都要变化,即问题的规模逐步简化,最终成为一个不再递归而得到答案的简单问题,这个简单问题就是递归出口。 如求n!,显然 当n=0时,可规定:n!=1 ,这就是递归出口 当n>0时,有n!=(n-1)!*n ,这就是递归公式(递归调用) 递归函数及其实现

  38. 递归函数及其实现 用递归算法求 n! 定义:函数 fact( n ) = n! fact( n-1 ) = ( n-1 )! 则有 fact( n ) = n fact( n-1 ) 已知 fact( 1 ) = 1

  39. 为了表述得直观清晰,我们定义两个结点:或结点和与结点。为了表述得直观清晰,我们定义两个结点:或结点和与结点。 图示的直观性与思维助力。 1、或结点 A为“或结点”,A依不同条件会有两种不同的取值, B 或C。结点用 表示。

  40. 如果有多于 2 种取值,可用下图: 条件为 Z1 , Z2 ,… ,Zn , A 取值为 B 或 C,…或 G

  41. 2、与结点 与结点要涂黑,相关联的 B 与 C 之间要用弧线连起来。 A 为与结点,A 的最终取值为 C 结点的值,但为了求得 C 的值,得先求出 B 结点的值, C 是B 的函数。

  42. 仍以求 n ! 为例画出如下与或图 A 为或结点;B 为直接可解结点,值为1; C 为与结点,当 n>1 时,A 的取值即 C 的值,而 C 的值即 E 的值,为了求得 E 的值,需要先求出 D 的值。D 值 fact( n-1 ) 乘以 n 即为 E 的值。

  43. 与结点可能有多个相关联的点,这时可描述为下图与结点可能有多个相关联的点,这时可描述为下图 A 结点的值最终为 D 的值,但为了求 D 需先求 B 和 C。从图上看, 先求左边的点才能求最右边的点的值,我们约定最右边 D 点的值就是 A 结点的值。

  44. 下面我们以 3!为例来画与或结点图,目的是体会 递归的含义。 C = 1 D = 2*C = 2 B = D = 2 E = 3*B = 3*2 = 6 A = E = 6

  45. 下面画出了调用和返回的递归示意图

  46. 从图可以想象: 欲求 fact( 3 ),先要求 fact( 2 );要求 fact( 2 ) 先求 fact( 1 )。就象剥一颗圆白菜,从外向里,一层层剥下来,到了菜心,遇到 1 的阶乘,其值为1,到达了递归的边界。然后再用 fact( n )=n*fact( n-1 ) 这个普遍公式,从里向外倒推回去得到 fact( n ) 的值。 为了把这个问题说得再透彻一点。我们画了如下的流程图:

  47. 为了形象地描述递归过程,将上图改画成下图

  48. 在这个图中“内层”与“外层”有着相同的结构。它们之间“你中有我,我中有你”,呈现相互依存的关系。在这个图中“内层”与“外层”有着相同的结构。它们之间“你中有我,我中有你”,呈现相互依存的关系。 为了进一步讲清递归的概念,将递归与递推做一比较。仍以求阶乘为例。 递推是从已知的初始条件出发,逐次去求所需要的阶乘值。 如求 3! 初始条件 fact( 1 ) = 1 fact( 2 ) =2 * fact( 1 ) = 2 fact( 3 ) = 3 * fact( 2 ) = 6

  49. 这相当于从菜心“推到”外层。 递归算法的出发点不放在初始条件上,放在求解的目标上,从所求的未知项出发逐次调用本身的求解过程,直到递归的边界(即初始条件)。就本例而言,读者会认为递归算法可能是多余的,费力而不讨好。但许多实际问题不可能或不容易找到显而易见的递推关系,这时递归算法就表现出了明显的优越性。下面我们将会看到,递归算法比较符合人的思维方式,逻辑性强,可将问题描述得简单扼要,具有良好的可读性,易于理解. 许多看来相当复杂,或难以下手的问题,如果能够使用递归算法就会使问题变得易于处理。下面举一个尽人皆知的例子河内(Hanoi)塔问题。

More Related