C程序设计课件:第5章 函数_第1页
C程序设计课件:第5章 函数_第2页
C程序设计课件:第5章 函数_第3页
C程序设计课件:第5章 函数_第4页
C程序设计课件:第5章 函数_第5页
已阅读5页,还剩66页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第五章 函 数1本章主要内容 5.1 函数概述 5.2 函数原型 5.3 全局变量与局部变量 函数的调用 5.4 函数调用机制 5.5 静态局部变量 函数的参数传递机制 5.6 递归函数 5.7 内联函数 5.8 重载函数 5.9 默认参数的函数 作业2理解什么是函数:过程模块区分函数声明与定义了解数学函数:数学库函数掌握全局和局部变量的用法了解递归函数学习目标:35.1 函数概述程序功能模块程序子程序C+ 语言: 程序函数程序结构: 4例: 编写一个对某个正整数有关的处理程序 主函数输入一个数逆序输出求该数范围内的水仙花数求该数范围内的素数求该数范围内的完数输出结果继续?结束55.1 函数概

2、述说明:1.源程序文件:一个源文件是一个编译单位,不是以函数为单位进行编译的2.C+程序由一个或多个源文件组成;分多个文件可以提高编译和调试的效率3.主程序只能有一个,程序执行自主程序开始,由主程序结束而结束 65.1 函数概述4.函数必须定义,定义时各函数相互独立,不能嵌套定义;除主函数外,函数间可以相互调用5.函数分类:从用户角度:库函数、自定义函数从 形 式:无参函数、有参函数7C+实用教程8返回类型 func ( 参数列表 ) ;返回类型 func ( ) ;void func ( 参数列表 ) ;void func ( ) ;int func1( int x ) return x *

3、 x ;int func2() return sizeof(int) ;void print( int x ) cout x endl ;void printCrLf() cout endl ;5.1 函数概述-函数的四种类型85.2 函数原型函数是面向对象程序设计中的基本抽象单元,是对功能的抽象函数声明的语法形式类型标识符 函数名 (形式参数表); 若无参数,写void是被初始化的内部变量,寿命和可见性仅限于函数内部若无返回值,写void9形式参数表type1 name1, type2 name2, ., typen namen函数的返回值由 return 语句给出,返回值的类型在声明时约定

4、。 例如 :return 0; return x+y ;无返回值的函数(void类型),不必写return语句。还可利用return语句改变执行顺序。5.2 函数原型105.2 函数原型在C+中,函数声明就是函数原型。函数原型不必包含参数的名字,只要包含参数的类型。例如: void funcA(int,float);函数定义 类型标识符 函数名(形式参数表) 语句序列; 115.2 函数原型函数的声明和函数的定义,在返回类型、函数名、参数个数、参数类型及参数顺序上必须完全一致,否则编译时出错。例如: int main() int a; float b; funcA(a,b); void fun

5、cA(int x,int y) / link error / 125.3 全局变量与局部变量 程序的内存区域代码区,存放程序的代码,即程序中的各个函数代码块。全局数据区,存放程序的全局数据和静态数据。堆区,存放程序的动态数据。栈区,存放程序的局部数据,即各个函数的数据。 135.3 全局变量与局部变量全局变量在函数外部定义的变量称全局变量作用域:从被定义的位置起,至文件结束处止说明:全局变量在程序执行的整个过程中,占用固定的内存单元(位于全局数据区)具有初始值(为0)可以被在其定义后的所有函数共同使用(解决“一个函数只能返回一个值”的问题)在同一源文件中,如果外部变量与局部变量同名,则:在局部

6、变量的作用域内,同名的全局变量不起作用145.3 全局变量与局部变量#include using namespace std; void f( int n);/ 函数原型声明int a = 8;/ 定义全局变量int main()coutaendl;f(10);coutaendl;return 0;void f(int n )/ 函数定义a = n;/ 将n的值赋给全局变量155.3 全局变量与局部变量局部变量只在某一函数内部定义的变量称局部变量,局部变量存放在栈区作用域:只局限于本函数内 说明不同函数的局部 变量可以同名形参是局部变量除本函数外,其它函数一概不能使用 复合语句中的局部变量 复

7、合语句可以看成是“程序块”,在其内部可另行定义变量分程序局部变量165.3 全局变量与局部变量#include using namespace std; void f( int n);/ 函数原型声明int a = 8;/ 定义全局变量int main()coutaendl;f(10);coutaendl;return 0;void f(int n )/ 函数定义int a; a = n;/ 将n的值赋给局部变量 coutaendl;17函数的调用调用前先说明函数原型或进行函数定义 例如: double power(double,int);调用形式 函数名(实参列表) 实际参数要和形式参数在个

8、数、类型及顺序上 保持一致 函数调用可出现在表达式中(有返回值的),也可作为一条单独的语句 例如: m=power(2.3,4); func();18函数的调用嵌套调用函数不允许嵌套定义,但可以嵌套调用。 例如: void funcA(int aa,int bb) int n=5; / funcB(n); 递归调用函数直接或间接调用自身。19例: 编写一个求x的n次方的函数#include double power (double, int); /函数声明int main( ) cout “5 to the power 2 is ” power(5,2) endl; /函数调用 double

9、power (double x, int n) /函数定义double val = 1.0;while (n-)val = val*x;return val; 运行结果:5 to the power 2 is 2520函数的调用函数调用的执行过程main( )调fun( )结束fun( )返回保存:返回地址当前现场恢复:主调程序现场返回地址21函数的调用嵌套调用main ( )调fun1 ( )结束fun1 ( )调fun2 ( )返回fun2 ( )返回int main( ) / fun1(a,b); / int fun1(int x,int y) / fun2(x); / int fun2

10、(int m) return (m*m); 22例:输入两个整数,求平方和。#include int main( ) int a,b; int fun1(int,int); /函数声明 cinab; cout“a、b的平方和:” fun1(a,b)endl; int fun1(int x,int y) int fun2(int); return (fun2(x)+fun2(y); int fun2(int m) return (m*m); 运行结果:3 4a、b的平方和:25home23函数的参数传递机制传递参数值在函数被调用时才分配形参的存储单元。实参可以是常量、变量或表达式。实参类型必须与

11、形参相符。24函数的参数传递机制传递参数值XN被调函数:主调函数:3 2.5AD = power(A,3) 2.53double power(double X, int N)home255.4 函数调用机制保护调用函数的运行状态和返回地址入栈建立被调用函数的栈空间传递参数将控制转给被调用函数 例如,下面的代码在主函数中调用一个函数,该函数又调用了另一个函数,它得到图5-3种所示的内存布局: 26void funcA(int,int);void funcB(int);int main( ) int a=6,b=12; funcA(a,b); void funcA(int aa,int bb) i

12、nt n=5; / funcB(n); void funcB(int s) int x; / 27图5-4是funcB( )返回到funcA( ), funcA( )又回到main( )时的栈内容。可以看出,返回到主函数后, funcA( ) 和funcB( )的局部变量和形参都消失,但对应内存中的内容还是存在的。285.5 静态局部变量静态局部变量:局部变量定义时,前面冠以 static 注意:位于全局数据区,系统默认初始化为0 静态局部变量只在函数第一次被调用时进行初始化 可见性:本函数内 295.5 静态局部变量存储类型:auto自动(动态、局部变量)static静态(可以全局,也可局部

13、变量)register寄存器(形参,局部变量)extern外部的全局变量C+规定:每个变量和函数有两个属性:存储类型和数据类型,并必须加以定义: 存储类型 数据类型 变量名列表;局部变量的存储类型缺省,默认为auto外部变量:指本文件外的全局变量,只定义一次,且在函数外定义 30/* ch5_2.cpp *#include void func();int n=1; /全局变量int main() static int a; / 静态局部变量 int b= -10; / 局部变量 cout a: a b: b n: n endl; b+=4; func(); cout a: a b: b n:

14、n endl; n+=10; func();void func() static int a=2; /静态局部变量 int b=5; / 局部变量 a+=2; n+=12; b+=5; cout a: a b: b n: n endl;运行结果为: a:0 b:-10 n:1 a:4 b:10 n:13 a:0 b:-6 n:13 a:6 b:10 n:3531include using namespace std;void count()int i = 0;static int j = 0; / 静态类型i+;j+;couti = i, j = jn;int main()count();co

15、unt();return 0;325.6 递归函数递归调用:直接或间接地调用自己直接递归调用:在函数f 中调用函数f 例如: void f() / f(); 间接递归调用:函数f 调用函数ff,而函数ff 调用函数f注意:要有终止递归调用的条件! 335.6 递归函数例:求n!分析:计算n!的公式如下:这是一个递归形式的公式,可用递归函数实现。345.6 递归函数递归过程的两个阶段:递推: 4!=43! 3!=32! 2!=21! 1!=10! 0!=1未知 已知回归:4!=43!=243!=32!=62!=21!=21!=10!=10!=1未知 已知35源程序:#include long f

16、ac(int n) long f; if (n0) coutn0,data error!endl; else if (n=0) f=1; else f=fac(n-1)*n; return f;36int main( ) long fac(int n); int n; long y; coutn; y=fac(n); coutn!=yendl;运行结果:Enter a positive integer:88!=4032037例:递归的执行情况分析 void print(int w) int i; if ( w!=0) print(w-1); for(i=1;i=w;+i) cout setw(

17、2) w ,; cout endl; 调用print(3)运行结果: 1, 2, 2, 3, 3, 3,38递归调用执行情况如下:主程序(1)print(w) w=3; 3print(2);(1)w=3 top(2) 压栈w=3w2print(1);(2)w=2 (1)w=3 top(3)压栈w=2w1print(0);(3)w=1 (2)w=2 (1)w=3 top(4)压栈w=1w0(4)w=0 (3)w=1 (2)w=2 (1)w=3 topw(3) 输出:2, 2(2) 2(1) 3top(4)输出:1(3) 1(2) 2(1) 3top(2) 输出:3, 3, 3 (1 ) 3top

18、返回(3) 1(2) 2(1) 3top(4) 0结束(1)void print(int w) int i; if ( w!=0) print(w-1); for(i=1;i=w;+i) cout setw(2) w ,; cout endl; 395.6 递归函数例:汉诺塔问题。有三根柱A、B、C。A柱上有N个盘子,大的在下,小的在上,要求把这N个盘子从A柱移到C柱,在移动过程中可以借助B柱,每次只允许移动一个盘,且在移动过程中在三根柱上都保持大盘在下,小盘在上。ABC40C+实用教程41演示:移动1个盘子的分解在A柱上只有一只盘子,假定盘号为 1,这时只需将该盘从 A 搬至 C,一次完成。

19、记为 move 1# from A to C ABC141C+实用教程42演示:移动2个盘子的分解第(1)步将1号盘从A移至B,这是为了让 2号盘能动;第(2)步将 2 号盘从A 移至 C;第(3)步再将 1 号盘从 B 移至 C;ABC21move 1# from A to B;move 2# from A to C;move 1# form B to C;42C+实用教程43演示:移动3个盘子的分解move (3, A, B, C)move (2, A, C, B)move (1, A, B, C)move (2, B, A, C)ABC21343C+实用教程44move (3, A, B

20、, C)move (2, A, C, B)move (1, A, B, C)move (1, A, C, B)move (1, C, A, B)move (1, A, B, C)move (2, B, A, C)move (1, B, C, A)move (1, B, A, C)move (1, A, B, C)ABC21344分析:将n 个盘子从A柱移到C柱可以分解为下面三个步骤:将A 上n-1个盘子移到 B柱上(借助C柱);把A柱上剩下的一个盘子移到C柱上;将n-1个盘子从B柱移到C柱上(借助A柱);事实上,上面三个步骤包含两种操作:将多个盘子从一个柱移到另一个柱上,这是一个递归的过程。

21、hanoi函数实现。将1个盘子从一个柱上移到另一柱上。用move函数实现。45#include void move( int n, char s, char d)coutn, sdendl;void hanoi( int n, char A , char B , char C )if (1 = n) move(n, A, C);else hanoi( n-1, A, C, B); move(n, A, C); hanoi( n-1, B, A, C);46int main( ) int m; coutm; coutthe steps to moving m diskes:C2, A-B1, C

22、-B3, A-C1, B-A2, B-C1, A-C475.6 递归函数递归的评价简化程序设计,使程序易读增加了系统开销(包括时间和空间)使用递归函数需要注意要有完成函数任务的语句递归的实现递归的运行过程递归的条件485.7 内联函数inline:也称内置函数、内嵌函数目的:减少开销、提高效率在编译时,象对待“宏”一样进行替换,程序运行时没有函数调用过程和函数返回定义、声明时:在前面冠以“inline”即可 491.内联函数的需要性例如,下面的代码中,频繁地调用一个小函数:/* ch5_3.cpp *#include int isnumber(char); /函数声明int main() ch

23、ar c; while(c=cin.get()!=n) if( isnumber(c) ) /调用一个小函数 cout you entered a digitn; else cout =0 & ch=9)? 1:0;5.7 内联函数50 程序中不断到设备中读取数据,频繁调用isnumber()函数。为了提高效率,可将程序改为:#include int main() char c; while(c=cin.get()!=n) if(c=0 & c=9)? 1:0) /修改处:直接计算表达式 cout you entered a digitn; else cout =0 & ch=9)? 1:0;

24、编译器看到inline后,为该函数创建一段代码,以便在后面每次碰到该函数的调用都用相应的一段代码来替换。523.先声明后调用#include int isnumber(char); /此处无inlineint main() char c; while(c=cin.get()!=n) if( isnumber(c) ) /调用一个小函数 cout you entered a digitn; else cout =0 & ch=9)? 1:0;535.7 内联函数4.内联函数的函数体限制如果被调用函数定义在被调用之前,且定义时冠以inline,则以后每次被调用均作内联函数处理。内联函数内不能出现s

25、witch、循环语句内联函数中不能有数组定义,也不能有任何静态类型的定义递归函数不能被定义成“内联”函数对常被调用的小而简单的函数进行“内联” 545.8 重载函数1. 重载的需要性 面向对象系统的3大特性之一的多态性就是通过重载实现的重载:即同名不同义,在不同的情况下可表现出不同的“行为”重载包括函数重载:多个函数同名,但执行的操作和操作对象不同操作符重载:一个运算符,可进行多种不同含义的解释,进行不同的操作 555.8 重载函数问题的提出:比较大小:2个整数比较、2个浮点数比较、.在C+中必须逐个定义不同名的多个函数希望:由系统自动判断,用户只要记住函数名即可重载:写多个同名函数,由系统根

26、据操作数自动判断究竟调用哪个函数 565.8 重载函数2.匹配重载函数的顺序 按如下先后顺序: (1) 寻找一个完全匹配,找到就调用 (2) 通过内部转换、然后寻找一个匹配,只要找到就调用 (3) 通过用户自己定义的转换寻找一个匹配,找到就调用 575.8 重载函数例如,重载函数print( )的匹配: void print(double); void print(int); void func() print(1); /匹配void print(int); print(1.0); /匹配void print(double); print(a); /匹配void print(int); pri

27、nt(3.1415f); /匹配void print(double); 585.8 重载函数C+允许int 到long,int到double 的转换。当实参是整数,而重载函数一个是long型参数,一个为double型参数时,应该给以一个显式转换。例如,对于重载函数print( )声明,其下面的函数调用将引起错误: void print(long); void print(double); void func(int a) print (a); /error:因为二义性 (double)a);595.8 重载函数3.使用说明 重载函数至少在参数个数、参数类型或参数顺序上有所不同,仅返回类型不同不

28、行不能用typedef定义的类型名来区别重载函数中的参数类型,因为“编译”时不区分其差别同名函数应具有相同的功能 605.9 默认参数的函数1.默认参数的目的函数在声明时可以预先给出默认的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。例如:int add(int x=5,int y=6) return x+y;int main( ) add(10,20); /10+20 add(10); /10+6 add( ); /5+661C+规定:实参与形参的个数必须相同,且类型相对应允许调用时不传递或部分不传递实参值,而采用缺省值例1:带缺省形参值的函数举例 #include

29、#include int get_volume(int length, int width=2, int height=3) coutsetw(5)length setw(5)width setw(5)height ; return length*width*height; 5.9 默认参数的函数62运行结果:Some box data is 10 12 15 1800Some box data is 10 12 3 360Some box data is 10 2 3 60Some box data is 10 7 3 210Some box data is 5 5 5 125int mai

30、n() int x = 10, y = 12, z = 15; cout Some box data is ; cout get_volume(x, y, z) endl; cout Some box data is ; cout get_volume(x, y) endl; cout Some box data is ; cout get_volume(x) endl; cout Some box data is ; cout get_volume(x, 7) endl; cout Some box data is ; cout get_volume(5, 5, 5) endl;635.9 默认参数的函数例2: #

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论