版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第4章 函数与编译预处理,掌握函数的概念、定义和调用方法。 理解递归的概念,并能运用递归的方法解决一些实际问题。 理解变量的作用域与生存期的概念,能够理解全局变量、局部变量、静态变量的概念和用法。,学习目标:,4.1 概 述,人们在求解一个复杂的问题的时候,通常采用逐步分解、分而治之的方法。也就是把一个大问题分解为几个比较容易求解的小问题,然后分别求解。程序员在设计一个复杂的应用程序时,往往也是把整个程序划分为若干个功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块象搭积木一样搭起来,这种在程序设计中分而治之的策略,被称为模块化程序设计方法。 函数:用于完成某一特定任务的一段程序
2、。 C/C+程序是由函数构成的,函数是C/C+程序的基本模块。,4.1 概 述,一个程序必须有且只有一个主函数(main( )函数),和若干个其它函数。 C/C+从main( )函数开始执行,由主函数调用其它函数,调用后流程还返回到main函数。其它函数之间也可以互相调用。,主函数,a,b,c,e,f,g,4.1 概 述,所有函数都是平等的。 在定义函数时是分别进行的,即函数不能嵌套定义。 函数间可以互相调用,但不能调用main函数。,主函数,a,b,c,e,f,g,4.1 概 述,库函数 C/C+系统所提供的函数,提供了丰富的功能。多少随系统而定,有一部分对所有的C/C+系统都有,格式也相同
3、,称为标准函数,还有一部分与系统有关。使用说明: A)资料 B)联机帮助 用户自定义函数 用户根据所需解决的问题而编写。函数定义是编写的一段代码(并不执行),函数定义后就可使用它,称为函数调用。,4.1 概 述,根据函数是否带有参数,将函数分为无参函数和有参函数。通常,调用函数时要给出参数的函数,称为有参函数;而调用函数时不需给出参数的函数称为无参函数。 根据函数的运算结果,函数又有返回值和无返回值之分。 使用函数的方式是:先说明(定义),后使用(调用)。,4.2 函数的定义与调用,函数定义的一般形式: 返回类型 函数名(参数表) 语句序列return 返回值; ,说明: 返回类型指函数返回的
4、值的类型,也称为:函数类型。 返回类型如果是 void ,意为无值返回。 返回类型说明若没有,指函数返回整型数。也就是:若函数返回整型类型的数据,可省略函数返回类型说明,否则不能省。 若参数表空,称为无参函数,否则称为有参函数。 无参函数参数表可写成(void)或写成()。,4.2.1 函数的定义,有参函数的几点说明: (1)定义函数时,函数的类型和函数体中return后的表达式值的类型应保持一致。如果两者不一致,则以函数类型为准,系统会自动进行类型转换。 (2)在函数体中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此函数只能返回一个函数值。 (3)对于不需要返
5、回值的函数,在函数定义中应规定函数返回值类型为void,但在函数体的中间要结束函数的执行,并返回调用处时,可使用不带表达式的return语句。此时return语句的格式为: return ;,4.2 函数的定义与调用,* * * * * * * * * * * How do you do! * * * * * * * * * * *,例:要求显示器输出:,#include #define NUM 11 void main() int i; for(i=0; iNUM; i+) cout*; coutendl; cout“How do you do !”endl; for(i=0; iNUM;
6、i+) cout*; coutendl; ,#include #define NUM 11 void print( ) int i; for (i=0; iNUM; i+) cout*; coutendl; void main() print(); cout“How do you do !”endl; print(); ,在出现函数调用时,程序控制转到函数,函数执行结束后,回到调用点(主函数),继续执行后续语句。,函数调用,函数定义,函数调用的方式,作为语句 printstar( );,作为表达式 c=max (a,b); coutmax (a,b);,作为函数参数 x=max(a,max(b
7、,c);,1) 被调用的函数必须是已存在的函数,2) 如果使用库函数,必须包含相应文件。 如 #include ,说明:,4.2.2 函数的调用,4.2.2 函数的调用,例5-1 输入两个实数,求出其中的大数。设计一个函数max求出两个实数中的大数。 #include float max(float x, float y) return ( xy ? x : y); void main(void) float a,b; cout ab; cout两个数中的大数为:max(a,b)n; ,当函数有返回值时,函数调用可出现在表达式中,也可作为一个函数调用语句来实现。当函数调用出现在表达式中时,用执
8、行函数体后返回的值参与表达式的运算。 对于没有返回值的函数,函数调用只能通过函数调用语句来实现。,在程序执行中要调用一个函数时,系统先要保护当前的现场,完成参数入栈等工作;然后转去执行被调用函数的函数体。 执行完被调用函数后,又要恢复现场,再接着执行函数调用后的其它语句。,4.2.2 函数的调用,#include int max (int a, int b) if (ab) return a; else return b; ,void main() int a,b,c, t; cina,b,c; t=max(a,b); t=max(t,c); couttendl; coutmax(a,b+10
9、)endl; ,函数定义中的参数称为函数的形式参数,一般称为形参。每个形参前应有形参的类型说明(不能写成int a,b),形参之间用逗号隔开。,return 的一般格式为: return 执行该语句时,首先计算表达式的值,将该值转换成函数的返回值类型,再将其作为函数的返回值,结束函数,将控制转到调用函数的地方继续执行。 若函数无返回值,在函数体中也可使用 return 语句结束函数的执行。,4.2.2 函数的调用,调用函数时要考虑到函数本身的参数; 调用标准库函数时,要包含相应的头文件 标准输入/输出函数 iostream.h 字符串函数 string.h 常用数学函数 math.h 调用自定
10、义函数时,要定义相应的实参,并给这些实参赋值。 实参与形参必须一一对应: “类型一致、位置一致、个数一致”,函数调用的过程,4.3 函数间的参数传递,4.3.1 传值调用,#include void change(int x, int y) int tmp; tmp=y; y=x; x=tmp; coutx=xy=yendl; void main() int x=3,y=4; coutx=x y=yendl; change(x,y); coutx=x y =yendl; ,change: x: y: tmp: main: x: 3 y: 4,3,4,4,3,4,函数实参与形参之间传递:值传递、
11、引用传递、地址传递,void main(void) int i=2, x=5, j=7; void fun(int,int); fun ( j, 6); couti=i, j= j,x= xendl; void fun ( int i, int j) int x=7; couti=i, j= j, x=xendl; ,输出: i=7, j=6, x=7 i=2, j=7, x=5,4.3.1 传值调用,计算实参表中各表达式; 将表达式的值依次赋给各形式参数; 执行函数体; 遇到return语句时,将控制返回到调用函数; 当return语句中包含表达式时,计算表达式的值并返回函数值; 无retu
12、rn语句时,执行到函数体末后返回调用函数; 参数以传值方式调用。,void add ( int x, int y, int z) z=x+y; x=x*x; y=y*y; cout(2) x=x y=y z=zendl; void main( ) int x=2,y=3, z=0; cout(1) x=x y=y z=zendl; add (x, y, z); cout(3) x=x y=y z=zendl; ,(1) x=2 y=3 z=0,(2) x=4 y=9 z=5,(3) x=2 y=3 z=0,4.3.2 引用调用,引用类型变量是其它变量的别名,对引用类型变量的操作实际上就是对被引
13、用变量的操作。 说明一个引用类型变量时,必须要用另一个变量对其初始化。说明引用型变量的语法格式为: 这里,refx 是一个引用类型变量,它是整型变量 x的一个别名,refx 与 x 使用同一内存空间。refx 称为对x 的引用,x 称为 refx 的引用对象。在说明引用类型变量 refx 之前变量 x 必须先说明。,4.3.2 引用调用,例: 引用的使用。 #include void main(void) int x, y=36; int ,4.3.2 引用调用,注意: 定义时必须初始化; 初始化值不能为常数; int 系统不为引用类型变量分配存储空间。 同一变量可定义多个别名。 引用类型变量
14、亦可定义别名。,4.3.2 引用调用,1引用作为函数的形参 当函数的形参为引用类型时,函数的传值方式称为引用传递。既可作为函数的输入参数,也可作为函数的输出参数。 当在函数体内改变了引用类型的参数后,能实际地改变实参的值,将新的值带回给调用者。 问题:当函数的形参是引用类型时,实参是否可以是表达式呢?,#include void swap(int ,4.3.2 引用调用,4.3.2 引用调用,2引用作为函数的返回值 当函数的返回值定义为引用类型时,函数所返回的值应是某个变量的别名,相当于返回了一个变量,因此可对该返回值进行赋值操作。 注意:当函数的返回值类型为引用类型时,在函数中只能返回静态变
15、量或全局变量的引用,不能返回非静态的局部变量的引用,因为这种类型的变量在函数执行结束时,其存储空间被释放,因此对它的引用是无效的。,例:将一个偶数分解为两个素数之和 #include #include #include int p(int n) if (nk; if (k%2) couterror!endl; exit(2); for (int i=2; i=k/2; i+) if (p(i) ,4.4 函数的原型说明,#include ,void main ( ) int a,b,t;,cinab; print(a,b); t=max(a,b); couttendl; ,void print
16、(int a, int b) int i;,for (i=0; imax(a,b); i+) cout*; coutendl; ,max(int x, int y) return (xy)?x:y; ,函数原型,函数若还没有定义,就先使用,就需要给出函数原型,此时只要提供函数返回值类型,函数名,形参类型即可。,4.4 函数的原型说明,函数原型说明的一般形式为: 函数类型标识符 函数名( 形参类型说明表 ) ; 说明: (1)函数原型说明与函数定义的区别在于:函数原型说明没有函数体部分,用分号结束,就像变量的声明。 (2)函数原型说明的位置可以在主调函数体内,也可以在主调函数外,只要放在对该函数
17、的调用语句之前,即使函数的定义放在其调用语句之后,也不会引起编译失败。 (3)函数原型说明时,形参类型说明表中可以缺省形参变量名,只给出形参类型。,4.5 函数的递归调用,函数的递归调用:在调用一个函数的过程中直接或间接地调用函数本身,称为函数的递归调用。,函数的递归调用,int f(int x ) int y,z ; . z=f(y); . return (2*z); ,4.5 函数的递归调用,n!=,1 n=0,1,(n-1)!*n n1,unsigned long f(unsigned long n) if ( n =1|n=0 ) return 1; else return n*f(n
18、-1); ,设计递归函数时,通常在函数体内先判断递归结束条件,再进行递归调用。如本例中,先判断n是否为0或1,若是,则结束递归;否则,根据递归公式进行递归调用。,4.5 函数的递归调用,递归函数的执行过程比较复杂,存在连续的递归调用(参数入栈)和回推的过程。以f(5)来说明递归函数的调用过程。因f(5)中参数不为1,故执行5*f(4)。同理,f(4)又变成4*f(3)。依次类推,直到出现函数调用f(1)时,将值1返回,再由此计算f(2).,这个过程成为回推。,5*f(4),5*24=120,4*f(3),4*6=24,3*f(2),3*2=6,2*f(1),2*1=2,1,递归过程,回推过程,
19、1,例:有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁。问第4个人多少岁,他说比第3个人大2岁。问第3个人多少岁,他说比第2个人大2岁。问第2个人多少岁,他说比第1个人大2岁。问第1个人多少岁,他说是10岁。请问第5个人多大?,age(5)=age(4)+2,age(4)=age(3)+2,age(3)=age(2)+2,age(2)=age(1)+2,age(1)=10,void main(void) int age(int); coutage(5)endl; ,int age ( int n ) int c; if (n=1) c=10; else c=age(n-1)+2; r
20、eturn c; ,int age ( int n ) int c; if (n= =1) c=10; else c=age(n-1)+2; return c; ,void main(void) int age(int); coutage(5)endl; ,age (5),n=5,c=age (4)+2,age (4),n=4,c=age (3)+2,age (3),n=3,c=age (2)+2,age (2),n=2,c=age (1)+2,age (1),n=1,c=10,return c,return c,c=12,return c,c=14,return c,c=16,return
21、c,c=18,虽然算法一致,但n不同,c不同,在内存中每一层函数变量所在的内存单元均不相同。必须有递归终止条件和递归公式。,递归,回推,例4.11 阅读下面程序,分析程序运行的结果。 void recu ( char c ) coutc ; if(c3)recu (c+1) ; coutc ; void main( ) recu (0); 程序运行后的输出结果是: 01233210,4.7 函数的重载,函数的重载是指完成不同功能的函数可以具有相同的函数名。 (C语言无此功能) 调用重载函数时,C+编译器根据实参的类型或实参的个数来确定应该调用哪一个函数。 注意: 重载函数的参数个数或参数类型必
22、须有不同 仅返回值类型不同时,不能定义为重载函数,例: 利用重载函数,分别计算两个整数、单精度实数和双精度实数中的大数。 #include int max(int x, int y) return ( xy?x:y ); float max(float a, float b) return ( ab?a:b ); double max(double m, double n) return ( mn?m:n ); void main(void) int a1, a2; float b1, b2; double c1, c2; cout a1 a2; cout b1b2; cout c1c2; c
23、outmax(a1,a2)= max(a1,a2) n; coutmax(b1,b2)= max(b1,b2) n; coutmax(c1,c2)= max(c1,c2) n; ,重载函数的定义,重载函数的调用,4.8 带有默认参数的函数,在C+中定义函数时,允许给参数指定一个缺省的值。在调用函数时,若明确给出了这种实参的值,则使用相应实参的值;若没有给出相应的实参,则使用缺省的值(C无此功能)。,#include float fact(int n = 10) float f=1; for ( int i=2; i=n; i+) f *=i; return f; void main(void)
24、 cout fact(5) n; cout fact( ) n; ,4.8 带有默认参数的函数,注意: 必须在函数调用前指定缺省参数的值 参数的缺省值可以是常量表达式,表达式中使用的量必须是常量 具有缺省值的函数参数可有多个,但缺省参数必须位于参数表中的最右边 同一个具有缺省参数的函数,在不同地方调用时可使用不同的缺省参数值,例: 输入长方体的长度,宽度和高度,求出长方体的体积。 #include float v(float, float=10, float=20); void main(void) float x, y, z; coutxyz; coutxy; coutx; cout第三个长
25、方体的体积为: v(x) n; float v(float a, float b, float c) return a*b*c; ,例: 对于同一个函数,可在不同的作用域内作不同的原型说明,定义不同的缺省参数值。 float fact(int n =10); . void bb(void) float fact(int =20); . x=fact( ); . float cc (void) float fact(int =30); . y=fact( ); . ,float dd(void) . z=fact( ); . float fact(int n) float f=1; for (i
26、nt i=2; i=n; i+) f *=i; return f; ,参数的缺省值为20,参数的缺省值为30,参数的缺省值为10,函数的定义,函数的原型说明,4.9 局部变量和全局变量,作用域是指程序中所说明的标识符在哪一个区间内有效,即在哪一个区间内可以使用该标识符。 C+中,作用域共分为五类:块作用域、文件作用域、函数原型作用域、函数作用域和类作用域。 根据作用域不同,可分为局部变量和全局变量。,4.9.1 局部变量,局部变量也称为内部变量,它是指在函数中定义的变量,其作用域只在本函数范围内。 在函数内定义的局部变量, 当退出函数时就不存在了。,float f1( int a) int b
27、,c; . ,float f2( int x, int y) int i, j; . ,void main(void ) int m, n; . ,说明: (1)主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量。 (2)形参变量是属于被调函数的局部变量。 (3)允许在不同的函数中使用相同的变量名。不同函数中定义的同名变量的作用域被限制于各自的函数体内,它们代表不同的对象,系统为它们分配不同的存储单元,互不干扰,也不会发生混淆。 (4)在复合语句中也可定义变量,也属于局部变量,其作用域只在复合语句的范围内。当复合语句中出现与其外部同名变量
28、时,在复合语句内则由复合语句定义的变量起作用。,4.9.1 局部变量,例4.15 分析下面程序的输出。 #include void main( ) int a=2 , b=3 ; coutfirst: atbn ; /A int a=5 ; b=a*3 ; coutsecond:atbn ; /B a+=b; /C coutthird:atbn ; ,程序的输出是: first: 2 3 second: 5 15 third: 17 15,void ex1(float x, float y) int i=10, j=20; int a; a=30; j=a; couti jendl; ,4.9
29、.2 全局变量,全局变量也称为外部变量,它是在函数外部定义的变量,其作用域是整个源程序。,p,q有效,int p=1, q=5; float f1( int a) int b,c; . ,char c1,c2; main( ) int m, n; . ,a,b,c有效,m,n有效,c1,c2有效,说明: (1)全局变量增加了函数间数据联系的通道。因为同一文件中的所有函数都能引用全局变量,因此如果在一个函数中改变了全局变量的值,就能影响到其它函数,相当于各个函数间有直接的传递通道。所以,可以利用这一特点通过函数调用能得到一个以上的值,而一般的函数调用只能由return语句带回一个返回值。 (2)
30、全局变量可以为所有的函数所共用。 (3)若在同一源文件中全局变量与局部变量同名,则在局部变量的作用范围内全局变量不起作用,即被“屏蔽”。,例4.17 全局变量与局部变量同名。 #include int a=10 ; /全局变量a int f1( int a ) /形参a return a*a ; int f2( int b ) int a; /局部变量a a=b+1; return a*a ; void main ( void ) coutThe result of f1 is: f1(2)n; coutThe result of f2 is: f2(2)n; couta=an; ,该程序的运
31、行结果为: The result of f1 is: 4 The result of f2 is: 9 a=10,如果在函数中要使用与其局部变量同名的全局变量,可以使用作用域运算符“:”来限定全局变量。 例4.18 在局部变量作用域内引用同名的全局变量。 #include double x=1.5 ; void main( void ) double x=5 ; cout全局变量: :xn; /A cout局部变量: xn; ,该程序的运行结果为: 全局变量: 1.5 局部变量: 5,例: #include void swap(float x, float y ) float t; t=x;
32、x=y; y=t; cout 函数swap:x=x y=y n; void main(void) float a=40, b=70; cout 主函数:a=a b=b n; swap(a,b); cout 主函数:a=a b=bn; ,#include float a=40, b=70; void swap(void) float t; t=a; a=b; b=t; cout 函数swap:a=a b=b n; void main(void) cout 主函数:a=a b=b n; swap(); cout 主函数:a=a b=bn; ,4.10 变量的存储类,存储类:规定了变量的生存期,确定
33、何时为变量分配内存空间及何时收回该空间。 变量说明格式: 标识符; 存储类可以是下面四种之一: 自动 auto 静态 static 寄存器 register 外部 extern,4.10 变量的存储类,自动类变量 : auto 按缺省规则,不加存储类说明的局部变量为自动的。 自动变量进入分程序时分配存储空间,退出分程序时,空间由系统回收。 自动类变量,若没有明确地赋初值,其初值是不确定的。 静态类变量 static 用 static 修饰的局部变量,静态变量的初始化仅在分配空间时做一次,若不初始化则系统自动置为 0。 静态变量在退出分程序后仍保留其值,但其值在分程序外不可见。,4.10 变量的
34、存储类,例如: #include int sum(int); void main() coutsum(4)endl; coutsum(4)endl; sum(int n) static int a=1; a+=n; return a; ,输出:5 9,4.10 变量的存储类,例 /设文件a1.cpp的内容为: #include static int i=200; int j=400; extern void f1(void); void main(void) coutitjn; f1( ); ,在说明全局变量时,加上修饰词 static,表示所说明的变量仅限于当前源程序文件内使用。,/ 设文件
35、a2.cpp 的内容为: #include extern int i; extern int j; void f1(void) i+=100; coutin; j+=100; coutjn; 程序编译时产生错误。,一个大程序由多个文件构成,由多人分别编写时,有可能在不同的文件中使用了同名但表示不同含义的全局变量。用 static 修饰全局变量,将其作用域限于一个文件中,就能很好地解决这个问题。,4.10 变量的存储类,寄存器类变量 register 用 register 修饰的局部变量,分配在寄存器中,以加快存储速度。 当资源限制做不到时,系统视为 auto。 静态变量和全局变量不能定义为寄存
36、器类变量。 外部类变量: extern 在函数外面说明的变量称全局变量。全局变量存储在全局变量区,在程序运行期间一直有效,程序运行完毕后由操作系统回收。 若使用的全局变量是先使用后定义或不在本文件中定义,类似于函数的原型说明,需要在使用前用 extern 加以说明。,4.10 变量的存储类,void f(int i) extern int x,y ; x+=i; y+=x; int x=100, y; void main(void) f(10); coutx=xt y=yn; f(20); coutx=xt y=yn; ,/文件c1.cpp float x; extern float f( )
37、; void main(void) coutf( )n; /文件c2.cpp extern float x; . float f( ) . ,void main(void) int x=10; int x=20; coutxendl; coutxendl; ,/20 /10,void main(void) int a=1,b=2,c=3; +a; c+=+b; int b=4, c; c=b*3; a+=c; coutfirst:atbtcendl; a+=c; coutsecond:atbtcendl; coutthird:atbtcendl; ,/a=2,/b=3, c=6,/b=4,/c=12,/a=14,/a=14,b=4,c=12,/a=26,/a=26,b=4,c=12,/a=26,b=3,c=6,int x=10; void main (void) int x=5; void cude(void); cude ( ); coutxendl; void cude(void) x=x*x*x ; ,/ 文件域中 x=1000,/main 函数域中 x=5; / 输出: 5,int f (int a) i
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度电气设备安装与维修合同
- 总经理聘请合同模板
- 房地产代理合同范文:委托与代理
- 代理合同:房地产估价委托协议书
- 广告业务经营权转让合同
- 产品责任保险合同专业版解析
- 自动化机器租赁协议
- 2024装修工程转包合同范本
- 年度长期合作协议范例
- 全面购销合同模板珍藏
- 君子自强不息课件
- 2022人教版高二英语新教材选择性必修全四册课文原文及翻译(英汉对照)
- WDZANYJY23低压电力电缆技术规格书
- 抗高血压药物基因检测课件
- 医院管理医院应急调配机制
- (公开课)文言文断句-完整版课件
- 小学生性教育调查问卷
- 医院感染管理质量持续改进反馈表
- 旅游行政管理第二章旅游行政管理体制课件
- 学生岗位实习家长(或法定监护人)知情同意书
- 卫生院关于召开基本公共卫生服务项目培训会的通知
评论
0/150
提交评论