收藏 分享(赏)

第3章 函数.ppt

上传人:fmgc7290 文档编号:6944413 上传时间:2019-04-28 格式:PPT 页数:72 大小:701.50KB
下载 相关 举报
第3章 函数.ppt_第1页
第1页 / 共72页
第3章 函数.ppt_第2页
第2页 / 共72页
第3章 函数.ppt_第3页
第3页 / 共72页
第3章 函数.ppt_第4页
第4页 / 共72页
第3章 函数.ppt_第5页
第5页 / 共72页
点击查看更多>>
资源描述

1、第3章 函数,C+语言程序设计,2,本章主要内容,函数的定义和调用 函数间的参数传递 内联函数 带默认形参值的函数 函数重载 C+系统函数 深度探索,3,函数的定义,函数是面向对象程序设计中,对功能的抽象 函数定义的语法形式 类型标识符 函数名(形式参数表) 语句序列 ,函数的声明与使用,是被初始化的内部变量,寿命和可见性仅限于函数内部,若无返回值,写void,4,函数的定义,形式参数表name1, name2, ., namen 函数的返回值 由 return 语句给出,例如: return 0 无返回值的函数(void类型),不必写return语句。,函数的声明与使用,5,函数的调用,调用

2、前先声明函数: 若函数定义在调用点之前,则无需另外声明; 若函数定义在调用点之后,则需要在调用函数前按如下形式声明函数原型:类型标识符 被调用函数名(含类型说明的形参表); 调用形式 函数名(实参列表) 嵌套调用 函数可以嵌套调用,但不允许嵌套定义。 递归调用 函数直接或间接调用自身。,函数的声明与使用,6,例3-1编写一个求x的n次方的函数,#include using namespace std;/计算x的n次方 double power(double x, int n) double val = 1.0;while (n-) val *= x;return val; int main()

3、 cout “5 to the power 2 is “ power(5, 2) endl;return 0; ,函数的声明与使用,7,运行结果: 5 to the power 2 is 25,例3-1编写一个求x的n次方的函数,函数的声明与使用,8,例3-2 数制转换,题目:输入一个8位二进制数,将其转换为十进制数输出。 例如:11012=1(23)+1(22)+0(21)+1(20)=1310 所以,如果输入1101,则应输出13,函数的声明与使用,#include using namespace std;/计算x的n次方 double power (double x, int n);in

4、t main() int value = 0;cout = 0; i-) char ch;cin ch;if (ch = 1)value += static_cast(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编写程

5、序求的值,其中arctan用如下形式的级数计算:直到级数某项绝对值不大于10-15为止;和x均为double型。,函数的声明与使用,#include 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,int main() double a = 16

6、.0 * arctan(1 / 5.0); double b = 4.0 * arctan(1 / 239.0); /注意:因为整数相除结果取整,如果参数写1/5,1/239,结果就都是0cout “PI = “ a - b endl;return 0; ,运行结果: PI=3.14159,12,13,例3-4,寻找并输出11999之间的数m,它满足m、m2和m3均为回文数。 回文:各位数字左右对称的整数。 例如:11满足上述条件 112=121,113=1331。 分析: 10取余的方法,从最低位开始,依次取出该数的各位数字。按反序重新构成新的数,比较与原数是否相等,若相等,则原数为回文。,

7、函数的声明与使用,#include 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,int main() for(unsigned m = 11; m 1000; m+)if (symm(m) ,15,运行结果: 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

8、=1367631,16,17,例3-5,计算如下公式,并输出结果:其中r、s的值由键盘输入。sin x的近似值按如下公式计算,计算精度为10-6:,函数的声明与使用,#include #include /对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) =

9、 TINY_VALUE); return g; ,18,int main() double k, r, s;cout r;cout s;if (r * r = s * s)k = sqrt(tsin(r) * tsin(r) + tsin(s) * tsin(s);elsek = 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则为胜

10、,游戏结束;和数为2、3或12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮、第三轮.直到某轮的和数等于点数则取胜,若在此前出现和数为7则为负。 由rolldice函数负责模拟投骰子、计算和数并输出和数。,函数的声明与使用,rand 函数原型:int rand(void); 所需头文件: 功能和返回值:求出并返回一个伪随机数 srand 函数原型:void srand(unsigned int seed); 参数:seed产生随机数的种子。 所需头文件: 功能:为使rand()产生一序列伪随机整数而设置起始点。使用1作为seed参数,可以重新初化rand()。,21,#inc

11、lude #include 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,enum GameStatus WIN, LOSE, PLAYING ;int main() int sum, myPoint;GameStatus status;unsigned se

12、ed; cout seed;/输入随机数种子srand(seed);/将种子传递给rand()sum = rollDice(); /第一轮投骰子、计算和数,23,switch (sum) case 7: /如果和数为7或11则为胜,状态为WINcase 11:status = WIN;break;case 2: /和数为2、3或12则为负,状态为LOSEcase 3: case 12:status = LOSE;break;default: /其它情况,游戏尚无结果,状态为PLAYING,记下点数,为下一轮做准备status = PLAYING;myPoint = sum;cout “poin

13、t is “ myPoint endl;break;,24,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;elsecout “player loses“ endl;return 0; ,25,运

14、行结果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()返回,28,例3-6 输入两个整数,求平方和。,#include using namespace std;int fun2(int m) return m * m; int fun1(int x,int y) return fun2(x) + fun2(y);

15、,函数的声明与使用,int main() int a, b;cout a b;cout “The sum of square of a and b: “ 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,递归调用,函数直接或间接地调用自身,称为递归调用。 递归过程的两个阶段: 递推:4!=43!3!=32!2!=21!1!=10!0!=1 未知 已知 回归: 4!=43!=243!=32!=62!=21!=21!=10!=1

16、0!=1 未知 已知,函数的声明与使用,31,例3-8 求n!,分析:计算n!的公式如下:这是一个递归形式的公式,应该用递归函数实现。,函数的声明与使用,源程序: #include using namespace std; unsigned fac(int n)unsigned f;if (n = 0)f = 1;elsef = fac(n - 1) * n;return f; ,32,int main() unsigned n;cout n;unsigned y = fac(n);cout n “! = “ y endl;return 0; 运行结果: Enter a positive in

17、teger:8 8! = 40320,33,34,例3-9,用递归法计算从n个人中选择k个人组成一个委员会的不同组合数。 分析:由n个人里选k个人的组合数= 由n-1个人里选k个人的组合数+由n-1个人里选k-1个人的组合数 当n = k或k = 0时,组合数为1,函数的声明与使用,#include using namespace std;int comm(int n, int k) if (k n)return 0;else if (n = k | k = 0)return 1;elsereturn comm(n - 1, k) + comm(n - 1, k - 1); int main(

18、) int n, k;cout n k;cout “C(n, k) = “ comm(n, k) endl;return 0; ,运行结果: 18 5 8568,35,36,例3-10汉诺塔问题,有三根针A、B、C。A针上有N个盘子,大的在下,小的在上,要求把这N个盘子从A针移到C针,在移动过程中可以借助B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。,函数的声明与使用,分析: 将n 个盘子从A针移到C针可以分解为下面三个步骤: 将A 上n-1个盘子移到 B针上(借助C针); 把A针上剩下的一个盘子移到C针上; 将n-1个盘子从B针移到C针上(借助A针); 事实上

19、,上面三个步骤包含两种操作: 将多个盘子从一个针移到另一个针上,这是一个递归的过程。 hanoi函数实现。 将1个盘子从一个针上移到另一针上。 用move函数实现。,37,#include using namespace std;/把src针的最上面一个盘子移动到dest针上 void move(char src, char dest) cout “ dest endl; /把n个盘子从src针移动到dest针,以medium针作为中介 void hanoi(int n, char src, char medium, char dest) if (n = 1)move(src, dest);e

20、lse hanoi(n - 1, src, dest, medium);move(src, dest);hanoi(n - 1, medium, src, dest); ,38,int main() int m;cout m;cout “the steps to moving “ m “ diskes:“ endl;hanoi(m,A,B,C);return 0; ,39,运行结果: Enter the number of diskes:3 the steps to moving 3 diskes: A C A B C B A C B A B C A C,40,41,函数的参数传递机制 传递参

21、数值,在函数被调用时才分配形参的存储单元。 实参可以是常量、变量或表达式。 实参类型必须与形参相符。 传递时是传递参数值,即单向传递。,函数的声明与使用,42,函数的参数传递机制 参数值传递举例,函数的声明与使用,43,例3-11 输入两个整数交换后输出,#include using namespace std;void swap(int a, int b) int t = a;a = b;b = t; ,函数的声明与使用,int main() int x = 5, y = 10;cout “x = “ x “ y = “ y endl;swap(x, y);cout “x = “ x “ y

22、 = “ y endl;return 0; 运行结果:x = 5 y = 10x = 5 y = 10,44,46,函数的参数传递 用引用做形参,引用( 声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。 一旦一个引用被初始化后,就不能改为指向其它对象。 引用可以作为形参 void swap(int &a, int &b) .,函数的声明与使用,47,例3-12 输入两个整数交换后输出,#include using namespace std; void swap(int ,函数的声明与使用,运行结果: x = 5 y = 10 x = 10 y = 5,swap(x,y);,

23、48,49,内联函数声明与使用,声明时使用关键字 inline。 编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销。 注意: 内联函数体内不能有循环语句和switch语句。 内联函数的声明必须出现在内联函数第一次被调用之前。 对内联函数不能进行异常接口声明。,内联函数,50,例3-14 内联函数应用举例,#include using namespace std;const double PI = 3.14159265358979; inline double calArea(double radius) return PI * radius * radius; int main(

24、) double r = 3.0;double area = calArea(r);cout area endl;return 0; ,内联函数,51,缺省形参值的作用,函数在声明时可以预先给出缺省的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的缺省形参值。 例如: int add(int x = 5,int y = 6) return x + y; int main() add(10,20);/10+20add(10); /10+6add(); /5+6 ,带缺省形参值的函数,52,缺省形参值的说明次序,有缺省参数的形参必须在形参列表的最后,也就是说缺省形参值的右面不能有无缺省值

25、的参数。因为调用时实参与形参的结合是从左向右的顺序。 例: int add(int x, int y = 5, int z = 6);/正确 int add(int x = 1, int y = 5, int z);/错误 int add(int x = 1, int y, int z = 6);/错误,带缺省形参值的函数,53,缺省形参值与函数的调用位置,如果一个函数有原型声明,且原型声明在定义之前,则缺省形参值必须在函数原型声明中给出;而如果只有函数的定义,或函数定义在前,则缺省形参值需在函数定义中给出。 例:,int add(int x = 5,int y = 6); /原型声明在前 i

26、nt main() add(); int add(int x,int y) /此处不能再指定缺省值return x + y; ,int add(int x = 5,int y = 6) /只有定义,没有原型声明return x + y; int main() add(); ,带缺省形参值的函数,54,重载函数的声明,C+允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用,便于记忆。 例:,函 数 重 载,55,注意事项,不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:,函 数 重 载,重载函数的形参必须不同:个数不同或类型不同。 编译程序将根

27、据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。,56,例3-16重载函数应用举例,编写两个名为sumOfSquare的重载函数,分别求两整数的平方和及两实数的平方和。#include using namespace std;int sumOfSquare(int a, int b) return a * a + b * b; double sumOfSquare(double a, double b) return a * a + b * b; ,函 数 重 载,int main() int m, n;cout m n;cout x y;cout “Their sum of squa

28、re: “ sumOfSquare(x, y) endl;return 0; ,57,运行结果: Enter two integer: 3 5 Their sum of square: 34 Enter two real number: 2.3 5.8 Their sum of square: 38.93,58,59,C+系统函数,C+的系统库中提供了几百个函数可供程序员使用。 例如:求平方根函数(sprt)、求绝对值函数(abs)等。 使用系统函数时要包含相应的头文件。 例如:cmath 或 math.h,使用C+系统函数,60,例3-17系统函数应用举例,题目: 从键盘输入一个角度值,求出

29、该角度的正弦值、余弦值和正切值。 分析: 系统函数中提供了求正弦值、余弦值和正切值的函数:sin()、cos()、tan(),函数的说明在头文件cmath中。,使用C+系统函数,#include #include using namespace std;const double PI = 3.14159265358979;int main() double angle;cout angle; /输入角度值double radian = angle * PI / 180; /转化为弧度值cout “sin(“ angle “) = “ sin(radian) endl;cout “cos(“ a

30、ngle “) = “ cos(radian) endl;cout “tan(“ angle “) = “ tan(radian) endl;return 0; ,运行结果: 30 sin(30)=0.5 cos(30)=0.866025 tan(30)=0.57735,61,标准函数与非标准函数,标准C+函数 C+标准中规定的函数; 各种编译环境普遍支持,因此用标准函数的程序移植性好; 很多标准C+函数继承自标准C,头文件以c开头:cmath,cstdlib,cstdio,ctime 非标准C+函数 与特定操作系统或编译环境相关; 在处理和操作系统相关事务时常常需要调用。,62,使用C+系统

31、函数,63,查找系统函数的使用说明,查编译系统的库函数手册 查联机帮助Visual C+.NET 2008联机帮助的使用方法: 进入MSDN Library for Visual Studio 2008 Development Tools and Languages- Visual Studio - Visual C+ - Reference - Libraries Reference-Run-Time Library - Run-Time Routines by Category,使用C+系统函数,形参和局部变量的存储,为什么不能为形参和局部变量分配固定地址? 他们仅在函数调用时生效,函数返

32、回后即失效,分配固定地址造成空间浪费 更重要的是,发生递归调用时,多次调用间的形参和局部变量应彼此独立 需要栈式存储,64,深 度 探 索,栈,栈是一种容纳数据的容器 数据只能从栈的一端存入(压入栈) 数据只能从栈的同一端取出(弹出栈),65,深 度 探 索,运行栈,运行栈是一段区域的内存空间 运行栈分为一个一个栈帧 每个栈帧对应一次函数调用 栈帧中包括: 本次函数调用的形参值 控制信息 局部变量值 一些临时数据 函数调用时,会一个栈帧被压入运行栈 返回时,会有一个栈帧被弹出,66,深 度 探 索,运行栈示意图,unsigned fac(unsigned n) unsigned f;if (n

33、 = 0)f = 1;elsef = fac(n - 1) * n;return f; int main() unsigned n;cin n;unsigned y = fac(n); ,67,深 度 探 索,函数调用的执行过程,栈指针esp:指向运行栈栈顶 帧指针ebp:定位形参和局部变量 传递参数:调用前把实参压入堆栈 函数调用时的几步关键操作 call指令:将下一条指令地址(返回地址)压入运行栈,转到函数入口地址 被调函数入口处:将当前ebp压入运行栈,用ebp保存esp,调整esp为局部变量留出空间 被调函数出口处:用ebp恢复esp,从运行栈中弹出ebp原值 ret指令:将返回地址从

34、运行栈弹出,转到返回地址,68,深 度 探 索,运行栈的数据分布,unsigned fac(unsigned n) unsigned f;if (n = 0)f = 1;elsef = fac(n - 1) * n;return f; ,69,形参和局部变量定位: ebp 8:形参n ebp + 4:局部变量f,深 度 探 索,函数声明的意义,以错误方式调用函数的危险性 函数的原型信息(参数个数和类型、返回值类型)在编译后即不存在; 如果不要求声明函数,以错误的方式(错误的参数数量或类型)调用函数,会产生不可预期的结果,但很多情况下不会给出错误提示。 函数原型是主调函数与被调函数间的协议 运行

35、结果错误 vs 编译错误 一个错误,与其被淹没在运行中,不如暴露在编译时。,70,深 度 探 索,C语言的反例,C语言允许 只声明函数名和返回类型,而不声明参数类型 不声明函数,直接调用 后果:隐蔽错误 如果给出add()的完整声明,则会自动进行类型转换。 声明带来了类型安全,double add(); int main() double s = add(1, 2);.return 0; double add(double a, double b) return a + b; ,71,72,小结与复习建议,主要内容 函数的声明和调用、函数间的参数传递、内联函数、带默认形参值的函数、函数重载、C+系统函数 达到的目标 学会将一段功能相对独立的程序写成一个函数,为下一章学习类和对象打好必要的基础。 实验任务 实验三,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报