《C++语言程序设计2.ppt》由会员分享,可在线阅读,更多相关《C++语言程序设计2.ppt(48页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、C+语言程序设计第二讲本讲主要内容n n函数的声明、定义和调用n n函数调用的执行过程n n变量作用域n n递归为什么要使用函数?L程序bad_program_1的代码好不好?L程序bad_program_2的代码好不好?L程序bad_program_3的代码好不好?n n引入函数的原因:将反复使用的代码写成函数,将反复使用的代码写成函数,便于复用便于复用便于复用便于复用将功能独立的代码写成函数,将功能独立的代码写成函数,便于阅读便于阅读便于阅读便于阅读什么是函数?n n函数由函数名函数名以及一组操作数类型一组操作数类型唯一唯一地表示n n函数的操作数操作数,又称形参形参(parameter)
2、形参在一对圆括号中声明形参在一对圆括号中声明形参在一对圆括号中声明形参在一对圆括号中声明形参之间用逗号分隔形参之间用逗号分隔形参之间用逗号分隔形参之间用逗号分隔n n函数执行的运算在一个称为函数体函数体(function body)的块语句中定义n n每一个函数都有一个相关联的返回类型返回类型(return type)函数声明、定义和调用n n函数声明:预先告知函数存在,并将其唯一预先告知函数存在,并将其唯一标识标识标识标识n n函数定义:函数的具体函数的具体实现实现实现实现n n函数调用:使函数使函数执行执行执行执行函数定义的语法形式函数返回值类型 函数名(形式参数表)函数体例:void s
3、how(void show(intint result)result)coutcout result result endlendl;函数声明的语法形式函数返回值类型 函数名(形式参数类型表);例:void show(void show(intint););但习惯上写为:void show(void show(intint result);result);函数调用的语法形式函数名(实际参数表);实参可以是字面值常量、变量或表达式实参可以是字面值常量、变量或表达式例:show(5);show(5);show(sum);show(sum);show(i*j/5+k);show(i*j/5+k);示
4、例n n无返回值函数及其调用n n有返回值函数及其调用注意事项即使函数不需要返回任何值,也必须将该即使函数不需要返回任何值,也必须将该函数的返回值类型指定为函数的返回值类型指定为void函函数可以不需要任何参数,此时参数表可数可以不需要任何参数,此时参数表可以为空,也可以声明为以为空,也可以声明为void,但圆括号不,但圆括号不能省略能省略函数名也是标识符函数名也是标识符如果函数有返回值,则必须保证所有的路如果函数有返回值,则必须保证所有的路径均有返回值径均有返回值思考题L下述哪些代码是非法的?为什么?1.test(doubletest(double v1,double v2)v1,doubl
5、e v2)2.intint manip(intmanip(int v1,v2)v1,v2)3.intint s()char*s;return s;s()char*s;return s;4.intint calc(intcalc(int v1,double v1);v1,double v1);5.intint calc(intcalc(int v1,double v1)v1,double v1)6.double double square(doublesquare(double x)return x*x;x)return x*x;7.void void printfabcprintfabc 注意
6、事项函数的所有返回值都必须和该函数的返回函数的所有返回值都必须和该函数的返回值类型保持一致值类型保持一致调用函数时,每一个实参的类型必须与对调用函数时,每一个实参的类型必须与对应的形参类型相同应的形参类型相同调用函数时,实参数目多于或少于形参表调用函数时,实参数目多于或少于形参表中参数数目均非法中参数数目均非法思考题L根据下述声明回答,以下那些调用非法?int DoTest(int x,int y);1.DoTest(“helloDoTest(“hello”,“world”);”,“world”);2.DoTest(2000);DoTest(2000);3.DoTest(2000,30,100
7、);DoTest(2000,30,100);4.DoTest(3.14,6.64);DoTest(3.14,6.64);函数调用的执行过程(1/2)主调函数主调函数和和被调函数被调函数是是相对相对的概念的概念函数从被调用的那一刻起开始执行函数从被调用的那一刻起开始执行函数在执行到函数在执行到return语句时停止执行语句时停止执行如果未碰到如果未碰到return语句,则执行到函数体语句,则执行到函数体的的”函数执行完毕后,返回调用者的调用位置,函数执行完毕后,返回调用者的调用位置,继续程序执行继续程序执行原理见书原理见书70页,图页,图3-1。函数调用的执行过程(2/2)准备调用函数时需要保存
8、现场准备调用函数时需要保存现场被调用函数执行完毕后需从调用位置继续被调用函数执行完毕后需从调用位置继续执行,此时需恢复现场执行,此时需恢复现场L何为保存现场?L何为恢复现场?L保存现场时保存的是什么?L恢复现场时恢复的是什么?L现场位于何处?对程序而言,内存什么样?内存是房间、数据是房客!内存是房间、数据是房客!每个房客至少要住一个房间!每个房客至少要住一个房间!找到房客的办法就是访问他所住的房间!找到房客的办法就是访问他所住的房间!内存地址内存地址(房间号)(房间号)内存空间内存空间(房间)(房间)对程序而言,内存什么样?例:short a=5;int b=100;char c=a;doub
9、le d=55.55;思考:上述代码如何执行?变量地址变量地址(房间号房间号)变量值变量值(房客)(房客)变量名变量名(房间代号房间代号)上页例子总结n n从程序角度:变量a是short类型的,初值为5;n n从内存角度:变量a在内存中的起始地址是1000,在内存中共占据2个地址单元,这些地址单元中存放的信息是5n n从程序角度:变量d是double类型的,初值为55.55;n n从内存角度:变量d在内存中的起始地址是1007,在内存中共占据8个地址单元,这些地址单元中存放的信息是55.55思考题L操作符&的新作用?L操作符*呢?L什么是指针?L指针类型的取值范围?L,&p,*p的关系?函数的
10、参数传递(1/4)L主调函数和被调函数间如何沟通?n nC+中的参数传递方式中的参数传递方式:非引用形参(值调用)非引用形参(值调用)引用形参(引用调用)引用形参(引用调用)根据例子思考例:定义:void Func(int x)调用:int a=5;Func(a);思考:C+用值传递方式进行上述参数传递。究竟如何实现的?参数传递过程步骤:将a的值复制给x;实质:从a所在的地址单元1000中取出值5,然后将该值复制至变量x所在的地址单元5000中5 5根据例子思考例:定义:void Func(int x)x=10;调用:int a=5;Func(a);cout a;思考:程序运行结果是?参数传递
11、过程步骤1:将a的值复制给x;实质:从a所在的地址单元1000中取出值5,然后将该值复制至变量x所在的地址单元5000中5 5 1010步骤2:改变x的值;实质:将x所在的地址单元5000中的值改为10 x的值改变了,的值改变了,a的值会改变吗?的值会改变吗?根据例子思考例:定义:void Func(int*x)*x=10;调用:int a(5);Func(&a);cout a;思考:如何实现上述的参数传递?参数传递过程步骤1:将a的地址复制给x;实质:将a的地址1000写入x所在的地址单元5000100010001010步骤2:改变x储存的地址中存的值;实质:取出x中储存的地址1000,然后
12、将该地址中的值改为10a的值改变了吗?的值改变了吗?x的值变了吗?的值变了吗?函数的参数传递(2/4)形参的变量作用域为形参的变量作用域为“函数内部函数内部”非引用类型的形参的初始化,是通过非引用类型的形参的初始化,是通过复制复制实参的值完成的!实参的值完成的!非引用类型的形参如果为指针,实现的是非引用类型的形参如果为指针,实现的是对该形参的对该形参的间接引用间接引用L用指针进行间接引用有哪些弊端?L什么情况不宜使用“非引用类型的形参”?函数的参数传递(3/4)以下情况不适宜以下情况不适宜“复制实参复制实参”:当需要在函数中修改实参的值时当需要在函数中修改实参的值时当需要以大型对象作为实参传递
13、时当需要以大型对象作为实参传递时当没有办法实现对象的复制时当没有办法实现对象的复制时C+提供了更好的参数传递方式:提供了更好的参数传递方式:引用传递引用传递何为引用?n n引用(reference)就是对象的另一个名字n n引用语法:在变量名前加“&”n n例:int val;int&refVal=val;引用必须用引用必须用 与该引用同类型的对象与该引用同类型的对象 初始化初始化引用是复合类型(引用是复合类型(compound type)注意!引用必须用引用必须用 与该引用同类型的对象与该引用同类型的对象 初始化初始化引用不可重新绑定引用不可重新绑定(一旦引用,终身引用)(一旦引用,终身引用
14、)思考题L找出下述代码中的错误:int iVal=1000;short&refVal=iVal;int&refVal2;int&refVal3=10;思考题L说明下述代码的意义:int i=1000,i2=2000;int&r=i,r2=i2;int i3=1000,&ri=i3;int&r3=i3,&r4=i2;思考题L下述代码输出什么?int i,&ri=i;i=5;ri=10;cout i ri endl;函数的参数传递(4/4)以下情况应使用以下情况应使用“引用形参引用形参”:当需要在函数中修改实参的值时当需要在函数中修改实参的值时当需要以大型对象作为实参传递时当需要以大型对象作为实参
15、传递时当没有办法实现对象的复制时当没有办法实现对象的复制时思考L使用引用有好处吗?L&的作用作用是?L*的作用作用是?L能做“取地址取地址”操作的条件条件是?L能做“解引用解引用”操作的条件条件是?思考L使用函数的优势?L使用函数的系统代价?内联函数(1/2)n n#define 的作用:语法:语法:#define A B#define A B作用:在整个代码中,作用:在整个代码中,A A都是都是B B的代号的代号编译时编译器将代码中所有的编译时编译器将代码中所有的AA替换成替换成替换成替换成BBn ninline 的作用:语法:语法:inline inline 函数定义函数定义作用:告诉编译
16、器,这个函数请当作作用:告诉编译器,这个函数请当作内联内联内联内联函数函数处理处理编译时编译器将代码中所有的该编译时编译器将代码中所有的该函数调用函数调用函数调用函数调用替换替换成该成该函数体内的代码函数体内的代码函数体内的代码函数体内的代码内联函数(2/2)n n内联函数示例:inline double CalArea(double radius)return 3.14*radius*radius;思考L什么样的函数适合指定为内联?inline 的作用仅仅是建议而已的作用仅仅是建议而已是否内联由编译器决定是否内联由编译器决定不用不用inline指定,也可能会被编译为内联指定,也可能会被编译为
17、内联带默认形参值的函数默认形参值的作用是:默认形参值的作用是:如果你不告诉我该做什么,我就按我如果你不告诉我该做什么,我就按我默认默认的方式工作的方式工作默认的形参值必须按照从右向左的顺序声默认的形参值必须按照从右向左的顺序声明明思考题L下述哪些是非法的?为什么?1.intint add(intadd(int x,x,intint y=5,y=5,intint z=6)z=6)2.intint add(intadd(int x=1,x=1,intint y,y,intint z=6)z=6)3.intint add(intadd(int x=1,x=1,intint y=5,y=5,intin
18、t z)z)4.intint add(intadd(int x=1,x=1,intint y,y,intint z)z)5.intint add(intadd(int x=1,x=1,intint y=5,y=5,intint z=10)z=10)思考题L如果某函数的参数x和参数y均有默认值,比较而言,x的默认值更常被使用。问:在函数声明中,x和y应以什么样的顺序出现?L如果你的代码想实现“计算x+y并输出结果”,怎么办?L如果x和y可以是整数、浮点数或复数,又怎么办?函数重载n n重载函数重载函数(overloaded function):出现在相同作用域的两个函数,如果具有出现在相同作用域
19、的两个函数,如果具有相同相同相同相同的名字的名字的名字的名字而而形参表形参表形参表形参表不同,则称为重载函数不同,则称为重载函数n n函数重载函数重载(function overloading):由编译器根据形参的类型和个数决定哪个函数由编译器根据形参的类型和个数决定哪个函数与当前函数调用是与当前函数调用是最佳匹配最佳匹配最佳匹配最佳匹配的过程的过程思考题L下述哪些不是重载函数?为什么?1.intint add(intadd(int x,x,intint y);y);float float add(floatadd(float x,float y);x,float y);2.intint ad
20、d(intadd(int x,x,intint y);y);intint add(intadd(int x,x,intint y,y,intint z);z);3.intint add(intadd(int););intint add(intadd(int x);x);思考题L下述哪些不是重载函数?为什么?4.intint add(intadd(int a);a);intint add(intadd(int x);x);5.intint add(intadd(int x);x);boolbool add(intadd(int x);x);6.typedeftypedef intint Data
21、TypeDataType;intint add(intadd(int x);x);intint add(DataTypeadd(DataType x);x);注意!重载只对相同作用域内的函数有效!重载只对相同作用域内的函数有效!不要为了重载而重载!不要为了重载而重载!嵌套调用和递归调用n n嵌套调用嵌套调用:A A调用调用B B,B B又调用了又调用了C C,C C又调用了又调用了DD但上述调用序列没有但上述调用序列没有“环环”n n递归调用递归调用:函数可以函数可以直接直接直接直接或或间接间接间接间接地地调用自身调用自身调用自身调用自身,称为递归调,称为递归调用用A A调用调用A AA A调用调用B B,B B又调用了又调用了C C,C C又调用了又调用了DD但上述调用序列中有但上述调用序列中有“环环”作业(1/1)n n请举出至少三个需要使用函数的理由n n请说明形参和实参的区别n n请说明引用和指针的异同n n请说明函数重载的优缺点n n作所有课后习题n n交课后习题 3-9、3-13
限制150内