1 / 64

第五章 函数

计算机程序设计. 第五章 函数. 计算机学院 613 教研室 唐晋韬. 本章内容. 模块化程序设计 预定义函数 自定义函数(原型、定义、调用) 函数重载 存储类别和作用域 递归函数 利用函数进行结构化程序设计. 5.1 模块化程序设计. …… …… 求 a 、 b 、 c 中最大者 将其值赋值给 m ……. …… …… m=max(a, b, c); ……. int max( int a…) { int x=(a>b)?a:b; x =(x>c)?x:c; return x; }.

boris-curry
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. 计算机程序设计 第五章 函数 计算机学院613教研室 唐晋韬

  2. 本章内容 计算机程序设计 2014 模块化程序设计 预定义函数 自定义函数(原型、定义、调用) 函数重载 存储类别和作用域 递归函数 利用函数进行结构化程序设计

  3. 5.1 模块化程序设计 …… …… 求a、b、c中最大者 将其值赋值给m …… …… …… m=max(a, b, c); …… int max(int a…) { int x=(a>b)?a:b; x =(x>c)?x:c; return x; } 计算机程序设计 2014 • 结构化程序设计方法将程序控制分解为顺序、选择、循环结构 • 都放在一个main函数中可以吗? • 将其中相对独立的功能提取出来:函数 • 用一条语句替代该模块:函数调用

  4. 认识函数 参数 结果 计算方法 f 参数 返回值 数学中的函数 一般表达: 计算机的计算 计算机程序设计 2014

  5. 5.1 模块化程序设计 计算机程序设计 2014 • 函数是C++程序构成的基础 • 任何C++程序至少包含一个函数——main()函数 • 函数也是类的方法的实现手段(面向对象) • 函数的作用 • 实现系统中按功能分解的各小任务 • 实现类对象的方法

  6. 5.1 模块化程序设计 函数一般用来完成一个相对独立的功能 main 函数 fun1 函数 fun2 函数 int main() { … fun1(); … return 0; } void fun1() { … int x =fun2(); … } int fun2() { int z; … return z; } 计算机程序设计 2014

  7. 5.1 模块化程序设计 计算机程序设计 2014 • 两类函数 • 预定义函数: C++提供了丰富的库函数,程序员可以在自己的程序中直接使用 • 用户自定义函数:用户根据需要编写的函数 • 一个C++程序可包含多个文件,一个文件可包含多个函数 • 所有函数是并列在一个层次的 • 所有函数通过main函数直接或间接调用

  8. 5.2 预定义函数的使用 计算机程序设计 2014 • C++ 中的预定义库 • C++ 中提供了丰富的预定义函数,称为“库函数” • 这些函数的声明都放在相应的头文件中 • 函数的声明包含如下部分 • 函数的名字 • 函数的参数数目及类型 • 函数返回值的类型

  9. 5.2 预定义函数的使用 计算机程序设计 2014 • 要使用预定义函数,必须先包括相应的头文件 • 如:数学运算函数的声明包含在math.h中,要使用这些函数,程序中必须加上 #include <math.h> …… m = sqrt(900.0);

  10. 5.3 函数定义与函数原型 计算机程序设计 2014 • 函数的优点 • 分而治之 • 有利于程序开发 • 避免代码重复 • 软件重用 • 重用已有的函数来构造新的程序 • 抽象-隐蔽内部的细节

  11. 5.3 函数定义与函数原型 <返回值类型><函数名>(<参数列表>) <函数体> 如果不写返回值类型? 默认为int 类型要一致 计算机程序设计 2014 • 函数定义格式 • 返回值类型:对函数返回值进行要求 • void - 函数没有返回值 int max ( int x, int y) { if ( x > y ) return x; return y; }

  12. 函数定义需注意的问题 计算机程序设计 2014 • 函数体内不能定义另外一个函数 • 所有的函数的定义都是并列在一个层次的 • 关于 return 语句 • 函数执行时,只要遇到 return语句,就会返回 • return 语句后面的<表达式>的值即为函数的返回值 • 函数返回值的类型必须要与<表达式>的类型匹配 • 所有的控制分支都要有 return 语句

  13. 函数定义需要注意的问题 void somefunc (int a, int b) { int c=(a+b)/2; if (c>=2) return c; } 计算机程序设计 2014 • 下面的函数定义存在什么问题? • 注意观察此时 VC 的编译信息 • 需要返回类型与实际返回类型不匹配 • 不是所有的控制分支都有返回值

  14. 函数定义需要的问题 char somefunc (int a, int b) { int c=(a+b)/2; if (c>=2) somefunc=c; else somefunc=-c; } 计算机程序设计 2014 • 函数定义中出现的标识符 • 函数中的形式参数都是局部变量 • “函数名”不是变量,不能够被赋值 • 指出如下函数定义中的问题

  15. 函数定义需要注意的问题 intsomefunc (inta) { intc; return c+a; } 计算机程序设计 2014 • 局部变量初始化问题 • 对于函数中新声明的局部变量,除了遵循“先声明、后使用”的原则外,还应遵循“使用前先初始化”的原则 • 对于任何一个变量,第一次出现在表达式右边出现之前,其值或由被用户输入,或者由程序赋值 • 观察下面函数的执行结果

  16. 例1:因子和 intsumOfFactors(int m) { int sum=0; cout << "The factors are :"; for (inti=1; i<=m; i++) if (m%i==0) { sum = sum+i; cout << i << " ; "; } cout << endl; return sum; } 现在,交换main函数和sumOfFactors函数的位置 • 设计一个函数,求一个正整数的所有因子之和。 • 如12的因子有1、2、3、4、6,则该函数返回16。 计算机程序设计 2014

  17. 5.3 函数定义与函数原型 数据输入 形式参数 数据处理 功能:函数名 返回值 数据输出 计算机程序设计 2014 • 函数原型 • 告诉编译器会有一个什么样的函数:名字叫什么,如果调用,需要什么参数,执行完后会给你一个什么结果 • 先声明后使用 int max ( int x, int y);

  18. 5.3 函数定义与函数原型 <返回值类型> <函数名>(<参数列表>); 计算机程序设计 2014 • 函数原型的构成 • 只需将“函数定义”中的<函数体>部分换为一个分号即可 • 注意:参数列表中形参的名字可以省略 • 函数原型的程序设计风格 • 用以声明函数,以符合“先声明、后使用”的原则 • 习惯上,一般将主函数定义放在前,被调用函数放在后,并将其原型放在主函数之前

  19. 5.4 函数调用 <函数名>(<实在参数列表>); 计算机程序设计 2014 • 函数调用的概念 • C++ 程序中,除了 main() 函数之外,任何一个函数都是通过直接或者被主函数调用执行 • 函数调用的形式 • 函数调用的步骤 • 传递参数 • 执行被调函数体 • 返回结果给调用者

  20. 5.4 函数调用 max (int , int); int max (3,5); max(3,5); int max (int , int); 计算机程序设计 2014 • 函数调用时的注意事项 • 实在参数与对应的形式参数类型要匹配、个数相同 • 对于无形参函数,调用该函数时圆括号不能少 • 练习 • 下面哪些调用是合法的?

  21. 5.4 函数调用 m = max(3, 5); int max ( int x, int y) { return (x>y)?x:y; } 5 计算机程序设计 2014 • 调用函数时一般要传递参数 • 传值和传引用 • 传值 • 把实在参数的值传递给函数的形式参数 • 函数的执行对实在参数没有影响 • 函数不需要修改实在参数时,用传值方式 • 避免意外改变

  22. 例子2:数据交换(传值) 计算机程序设计 2014 • 设计一个函数swap,实现两个变量值的交换 • void swap(int x, int y); • 传给它两个值,能实现交换吗?

  23. 例子2:参数传递(传值) int main() { int a=3, b=5; swap(a,b); cout<<a<<endl; cout<<b<<endl; return 0; } void swap(int x, int y) { int z = x; x = y; y = z; } 计算机程序设计 2014

  24. 例子2:参数传递(传值) swap(a, b); … void swap(int x, int y) { int z = x; x = y; y = z; } 3 5 a 3 x 5 b 5 y 3 z 3 计算机程序设计 2014 调用发生后的具体过程(传值)

  25. 参数传递 void swap(int &x, int &y) { int z = x; x = y; y = z; } 计算机程序设计 2014 • 引用型参数 • 为使被调函数访问调用它的实参,C++ 还提供了另外一种类型的参数 —— 引用型参数

  26. 5.4 函数调用 计算机程序设计 2014 • 传引用 • 形式参数采用引用参数 • 形参和实参共享存储空间——实参的存储空间 • 函数的执行可以改变实在参数——通过修改形式参数 • 要求实在参数有“左值性质”——实参必须有存储空间

  27. 参数传递(传引用) void swap(int &x, int &y) { int z = x; x = y; y = z; } swap(a, b); … a 5 3 x b 5 y 3 z 3 计算机程序设计 2014 调用发生后的具体过程(传引用)

  28. 5.4 函数调用 • 需要返回多个值怎么办? • 哥德巴赫猜想的验证:所有大于2的偶数都可以分解为两个素数之和。 • 函数:?goldbach(n),需要返回一个布尔值表示对于偶数n该猜想是否成立,但也需要返回两个素数的值,怎么办? 计算机程序设计 2014

  29. 5.4 函数调用 boolgoldbach(intevenNum, int & result1, int &result2) { for(inti=1;i<evenNum/2;i++){ if(isPrime(i) && isPrime(evenNum-i)){ .... } } } 计算机程序设计 2014 • 传引用的一个用处 • 在某些时候,可以引用型参数替代返回值 • 当函数有多个返回值时,可以使用引用型参数

  30. 5.4 函数调用 计算机程序设计 2014 • 默认参数 • 可以为形式参数提供默认值 • 函数调用时提供了实在参数则使用实在参数 • 没有则使用默认参数

  31. 5.4.3 函数的默认参数 intcubeVolume(int , intwid=1, inthei=1); Why? 计算机程序设计 2014 • 注意事项 • 默认参数应在函数名第一次出现时指定 • 函数原型,或者函数定义(没有函数原型时) 如在函数声明时使用默认参数 • 默认参数一定是参数列表中最右边的参数 • 个数可为1个、多个或全部 • 但一定是最右边的连续多个

  32. . 默认参数举例 intcubeVolume(intlen=1 , intwid=1, inthei); intcubeVolume(int , intwid=1, inthei=1); cubeVolume(2, 3, 4); // 24,正常调用 cubeVolume(2, 3); //6,缺省最后一个参数 cubeVolume(2); //2,缺省最后两个参数 计算机程序设计 2014 • 例5-4:使用默认参数计算长方体体积 • 下面函数调用都是正确的

  33. 实践练习(Part 1) 计算机程序设计 2014 • 写一个函数将以时、分、秒格式的耗时数转换为以秒为单位的耗时数,并在main函数中调用它。 • 比如:1小时15分20秒的耗时数的转换结果是:4500秒 • 编写一个函数,判断一个整数是否是素数。 • 然后依托该函数验证哥德巴赫猜想:任何一个大于等于6的偶数都可以表示成两个素数之和 • 输入任意大于6的偶数,如果可以分解,输出两个素数,否则输出提示字符

  34. 5.5 函数重载 int main(){ cout << abs(-2) << endl; cout << abs(2.54f) << endl; double d = -3.3E-8 cout << abs(d) << endl; } 计算机程序设计 2014 • C++允许定义多个同名函数表示类似的操作——函数重载 • 这些函数必须有不同的参数(参数的个数、类型或顺序不同) • 调用重载函数时,编译器通过检查实在参数的个数、类型和顺序来确定相应的被调用函数 int abs(inti); float abs(float f); long abs(long l); double abs(double d);

  35. 5.6 存储类别和作用域 计算机程序设计 2014 auto,register,extern,static 存储期:在内存中的存在期 作用域:在程序中可以引用该变量的区域 连接:变量在哪些源文件中能够被识别

  36. 5.6 存储类别和作用域 计算机程序设计 2014 • 自动存储 • 在定义的程序块中建立、存在和撤销 • 没有缺省值 • auto: 局部变量(包括形式参数)的缺省说明符 • auto double x, y; • register: 为变量分配高速寄存器 • 只能用于auto变量 • register int counter = 1;

  37. 5.6 存储类别和作用域 static int a; extern intoutVar; 计算机程序设计 2014 • 静态存储:变量在整个程序运行期间都存在 • 缺省值为0 • static: 可以用于函数中的局部变量 • 函数运行结束,变量的值依然存在 • 只能在定义变量的函数中访问该变量 • extern: 全局变量和函数名的缺省定义 • 在所有的函数中都能访问 • 多个文件使用同一个全局变量时,需要显式说明

  38. 5.6 存储类别和作用域 计算机程序设计 2014 • 四种作用域 • 文件作用域 • 函数作用域 • 块作用域 • 函数原型作用域

  39. 5.6 存储类别和作用域 #include <stdio.h> int x = 1; /* global variable */ int main() { ... } 计算机程序设计 2014 • 文件作用域 • 在函数外面定义的标识符,能够被从标识符说明到文件结束之间的所有函数引用 • 全局变量、函数定义、函数原型

  40. 5.6 存储类别和作用域 #include <stdio.h> int main() { ... goto L1; ... L1: printf(...); ... } 计算机程序设计 2014 • 函数作用域 • 只能在函数体中引用 • 标号是唯一具有函数作用域的标识符

  41. 5.6 存储类别和作用域 计算机程序设计 2014 • 块作用域 • 在程序块中声明的标识符具有块作用域 • 块作用域开始于声明处,结束于程序块的右花括号 • 函数的形式参数、函数的局部变量、在复合语句中声明的变量具有块作用域 • 如果外层块和内层块有相同名字的变量,外层说明会被内层说明屏蔽(最近嵌套原则)

  42. 5.6 存储类别和作用域 #include <stdio.h> int main() { int x = 5; printf("local x is %d\n", x ); { int x = 7; printf( "x in inner scope is %d\n", x); } printf("local x is %d\n", x ); return 0; } 计算机程序设计 2014 块作用域示例

  43. 5.6 存储类别和作用域 void a(int param1, int param2); void b(float param1); int main() { int pram1; ... } 计算机程序设计 2014 • 函数原型作用域 • 函数原型参数表中的参数名标识符具有函数原型作用域 • 函数原型中的参数名可以省略

  44. 课堂练习 计算机程序设计 2014 (数据处理)C语言将浮点数转换成整数时采用直接截断的方法,也就是说4.9转换成整数是4。编写函数round,将浮点数转换成整数,采用4舍5入的方式。并编写主函数测试它。 如果保留n(n>=0)位小数进行四舍五入呢?Round函数该怎么编写?

  45. 5.8 递归函数 计算机程序设计 2014 • 递归的定义 • 所谓“递归”,是指函数直接或者间接调用自身的行为 • 递归的作用 • 实际中有许多问题,其解决过程依赖于类似问题的解决,只不过后者规模更小 • 示例 • 从另一个角度看

  46. 5.8 递归函数 long factorial (long number) { if (number <=1) return 1; else return number *factorial(number-1); } 计算机程序设计 2014 • 通过解决简单的问题,达到解决整个问题的目的

  47. factorial(number) number: 1 { ... return 1 ... } factorial(number) number: 2 { ... return (2*factorial(1)) ... } 1 factorial(number) number: 3 { ... return (3*factorial(2)) ... } 2 factorial(number) number: 4 { ... return (4*factorial(3)) ... } 6 24 factorial(number) number: 5 { ... return (5*factorial(4)) ... } 120 计算机程序设计 2014

  48. 5.8 递归函数(练习) 计算机程序设计 2014 已知“菲波那契”数列为0,1,1,2,3,5, 8...,定义如下 试用递归实现计算该数列第 n 项的函数

  49. f( 3 ) return f( 2 ) + f( 1 ) return f( 1 ) f( 0 ) return 1 + return 1 return 0 5.8 递归函数(练习) intfibonacci(unsigned int n) { if (n < 2) returnn; else returnfibonacci(n-1)+fibonacci(n-2); } 计算机程序设计 2014 Fibonacci数列:0,1,1,2,3,5, 8…

  50. 5.8 递归函数 计算机程序设计 2014 • 递归函数设计的原则 • 分解问题结构:准确分解问题的递归结构,分清楚哪些是当前能够直接处理的,哪些是当前不能处理、但能分解为和原问题相似,但结构简单的问题 • 根据问题的结构特征规划递归算法:当前能直接解决的问题就设计相应的算法解决;不能直接解决的,同归递归调用算法自身来解决

More Related