第2章 第5讲 函数_第1页
第2章 第5讲 函数_第2页
第2章 第5讲 函数_第3页
第2章 第5讲 函数_第4页
第2章 第5讲 函数_第5页
已阅读5页,还剩64页未读 继续免费阅读

下载本文档

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

文档简介

第5讲函数授课内容5.1函数概述5.2函数的定义5.3函数的调用5.4函数原型5.5函数间的参数传递5.6函数重载5.7变量的持续性、作用域、链接性5.8内联函数5.9带有默认参数的函数5.1

函数概述函数概述函数是构成程序的基本模块,每个函数完成一个计算或执行一个特定的动作,具有相对独立的功能。通过函数,可以把一个复杂任务分解成为若干个易于解决的小任务。充分体现结构化程序设计“自顶向下逐步求精”的设计思想。C++中三种类型的函数:主函数main()标准库函数用户自定义函数#include<iostream>#include<algorithm>intmain(){ inta[10]; for(inti=0;i<10;++i) { a[i]=rand()%100; std::cout<<a[i]<<""; } cout<<endl; sort(a,a+10); for(inti=0;i<10;++i) { std::cout<<a[i]<<""; } return0;}sort(a,a+10);#include<algorithm>5.2

函数的定义函数的定义函数必须先定义,后使用。定义函数就是编写完成函数功能的程序块。定义函数的一般格式为:

<函数返回值类型><函数名>(<参数说明>) { <语句序列> <return<表达式>> }函数体函数返回值类型函数返回值类型:表明了调用该函数后所得到的函数返回值的类型。intf(){ return1.4+2.8;}intmain(){cout<<f();return0;}函数返回值类型说明如果某一函数确实没有返回值,则使用说明符void。 例如:

voidadd(inta,intb){ cout<<a+b; return;}

//可以省略编写计算n!的函数intfac(intn)//计算阶乘n!{ intresult=1; if(n<0) {return-1;} elseif(n==0) {return1;} while(n>1) {result*=n;n--;} returnresult;}n不能太大5.3

函数的调用函数的调用函数调用形式:<函数名>(<实参表>)实参表是调用函数时所提供的实在参数值,这些参数值可以是常量、变量或者表达式。调用函数时提供给被调函数的实参应该与函数形参表中的形参一一对应。类型一致、位置一致、个数一致。函数调用和返回的过程主调函数和被调函数之间的信息交换是通过参数的结合和return语句来实现的。数据流程是:在主调函数中,先给实参赋值通过函数调用,将数据从主调函数带到被调函数形参带值后,被调函数即可进行相应的数据处理如果被调函数有返回值,通过return语句传回到主调函数函数调用和返回的过程intf(intx){ intb=1; returnx+b;}intmain(){ inta=3; ints=f(a); return0;}af()main()运行状态及返回地址xb331栈顶栈底temp:4s45.4

函数原形intmain(){ inta,b; cin>>a>>b; cout<<max(a,b)<<endl; return0;}intmax(intx,inty) { returnx>y?x:y;}intmax(intx,inty);函数原型函数调用函数定义intmax(int,int);例求两数中的最大数函数原形与函数定义的区别函数原型没有函数体,用分号结束,参数名也可以省略。5.5

函数间的参数传递函数间的参数传递实参与形参结合的方式有三种:值调用地址调用:和值调用的本质相同引用调用voidswap(intx,inty){ inttmp=x; x=y; y=tmp;}intmain(){ inta=1,b=2; cout<<"a="<<a<<"b="<<b<<endl; swap(a,b); cout<<"a="<<a<<"b="<<b<<endl; return0;}输出a=1b=2a=1b=2baswap()main()运行状态及返回地址xytem1212栈顶栈底121值调用值调用在调用时仅将实参的值赋给形参,在函数中对形参值的任何修改都不会影响到实参的值。引用调用值调用的缺点:被调函数向主调函数传递的数据只能通过返回值来实现,有时显得不够用。为了解决这个问题,C++引入了一个新的调用机制:引用调用。引用引用是给一个已经定义的变量重新起一个别名,而不是定义一个新的变量,定义的格式为:<类型>&<引用名>=<变量>;

<类型>&<引用名>(<变量>);例如:intnumber=10; int&newnum=number;intnumber=10, int&newnum(number);含义:通过引用名与通过被引用的变量的变量名变访问变量效果一样。引用和指针inta=10; int&ra=a; int*pa=&a; cout<<a; cout<<ra; cout<<pa; cout<<*pa;paa:0X0012ff7010ra0X0012ff70引用注意:

声明一个引用时,必须同时初始化。该引用名不能再作为其他变量的别名。引用inta=3,&m=a;intn=m;inta=3,&m=a;int*p=&m;inta1;int&b;b=a1;inta1=1,a2=2;int&b=a1;b=a2;inti=100,&refi=i;refi+=100;voidswap(int&x,int&y){ inttmp=x; x=y; y=tmp;}intmain(){ inta=1,b=2; cout<<"a="<<a<<"

b="<<b<<endl;

swap(a,b); cout<<"a="<<a<<"

b="<<b<<endl; return0;}输出a=1

b=2 a=2

b=1baswap()main()运行状态及返回地址xytmp12栈顶栈底121voidswap(int*x,int*y){ inttmp=*x; *x=*y; *y=tmp;}intmain(){ inta=1,b=2; cout<<"a="<<a<<"b="<<b<<endl;

swap(&a,&b); cout<<"a="<<a<<"b="<<b<<endl; return0;}输出a=1

b=2 a=2

b=1b:0X0012ff74a:0X0012ff70swap()main()运行状态及返回地址xytmp120X0012ff700X0012ff74121与指针作参数的地址传递相比:引用作形参,方便、直观。C++编程中形参被声明为引用的时候远多于形参被声明为指针的时候。int*f(int*y,int&x){ inta=5; int*s=&a; y=s; x=a; returns;}intmain(){ inta=6,b=7; int*pa=&a; int*x;

x=f(pa,b); cout<<"*x="<<*x<<endl; cout<<"*pa="<<*pa<<endl; cout<<"b="<<b<<endl; return0;}引用数组的引用inta[5]={1,2,3,4,5}; int(&ra)[5]=a; cout<<ra[2]; ra[4]=10; cout<<a[4]; int(&rb)[10]=a;5.6

函数重载函数重载例子#include<iostream>usingnamespacestd;intabs(intx){ cout<<"intabs"; returnx>0?x:-x;}doubleabs(doublex){ cout<<"doubleabs"; returnx>0?x:-x;}intmain(){ intx1=-1; doublex2=-2.5; inta=abs(x1); doubleb=abs(x2); cout<<a<<endl <<b<<endl return0;}函数重载的方法参数类型上不同的函数重载intmax(inta,intb); floatmax(floata,floatb); doublemax(doublea,doubleb);参数个数上不同的函数重载intmin(inta,intb);intmin(inta,intb,intc);intmin(inta,intb,intc,intd);函数重载注意(overloading)intget_value(){return0;} floatget_value(){return1.2f;}

intmain() { ints=get_value(); return0; }

不能仅靠函数的返回值类型的不同进行函数重载,因为编译程序选择相应的重载函数时返回值不起作用。

floatget_value(){return1.2f;}intget_value(){return0;}函数重载注意(overloading)另外,不要重载毫不相干的函数,这样做从根本上违反了它的初衷重载函数的调用voidfunc(charc){cout<<c;} voidfunc(doubled){cout<<d;} voidfunc(double*pD){cout<<*pD;}func('A');

调用规则如果函数调用时的实参类型与一个重载函数的形参类型完全匹配,则调用该重载函数;如果找不到与实际参数类型完全匹配的函数,但如果通过类型转换后能找到完全匹配的函数,编译程序调用该重载函数。'A'—>double重载函数的调用重载函数调用的二义性C++编译程序无法在多个重载函数中选择正确的函数调用,会导致整个程序无法编译。例:voidfunc(floatc){cout<<c;} voidfunc(doubled){cout<<d;}func(3.14);func('a');5.7

变量的持续性、作用域、链接性

#include<iostream>

usingnamespacestd;

intc=10; staticintd=10; voidf() { inta=10;++a;cout<<a;staticintb=10;++b;cout<<b;} #include<iostream>

usingnamespacestd;voidf();intmain(){ cout<<a; cout<<b; cout<<c; cout<<d; f(); f(); return0;}a.cpp的内容b.cpp的内容变量的持续性、作用域、链接性C++中每个变量可以通过三个属性来衡量作用域:描述变量的作用范围代码块文件链接性:描述在一个文件中定义的变量是否可以在外部文件中被使用无链接有链接变量的持续性、作用域、链接性持续性:描述变量在程序运行期间的存在时间的长短自动当程序运行到自动变量作用域中时才会为自动变量分配相应的存储空间,一旦退出自动变量的作用域,程序会释放自动变量占用的存储空间,因此自动变量的生存期是从其定义开始的地方到自动变量的所处的作用域结束的地方。生存期与可见期一致。变量的持续性、作用域、链接性持续性:描述变量在程序运行期间的存在时间的长短静态静态变量被分配存储空间后,该变量所占据的存储空间会一直存在,直到程序结束,如有初值的话,只在第一次分配时设置,以后就不再设置初值。生存期与可见期不一致。变量的持续性、作用域、链接性a.cpp的内容 intc=10; staticintd=10; voidf() { inta=10;++a;cout<<a;staticintb=10;++b;cout<<b;}a:作用域:代码块持续性:自动链接性:无链接b:作用域:代码块持续性:静态链接性:无链接c:作用域:文件持续性:静态链接性:有链接d:作用域:文件持续性:静态链接性:无链接

#include<iostream>

usingnamespacestd;

intc=10; staticintd=10; voidf() { inta=10;++a;cout<<a;staticintb=10;++b;cout<<b;} #include<iostream>

usingnamespacestd;voidf();intmain(){ cout<<a; cout<<b; cout<<c; cout<<d; f(); f(); return0;}a.cpp的内容b.cpp的内容//error//error//errorexternintc;

#include<iostream>

usingnamespacestd; constinta=10; voidf() {

cout<<a;} #include<iostream>

usingnamespacestd;voidf();constinta=100;intmain(){ cout<<a; f(); return0;}a.cpp的内容b.cpp的内容变量的持续性、作用域、链接性变量类型作用域持续性链接性代码块中定义(无static)代码块自动无代码块中定义(有static)代码块静态无函数外面定义(无static)文件静态有函数外面定义(有static)文件静态无5.8

内联函数内联函数在调用函数时系统样需要作许多隐操作(保护现场、传递参数、控制指令的转移)这些隐操作所用的开销可能比执行一些简单的函数的函数体的开销还要大。当这样的函数被频繁调用时,附加的时间开销将大得不容忽视。内联函数boolIsNum(charch){return(ch>='0'&&ch<='9')?true:false;}intmain(){ charch;intcount=0; for(inti=0;i<10;++i) { cin>>ch; if(IsNum(ch)==true) {++count;} } return0;}(ch>='0'&&ch<='9')但这个办法有缺点是程序可读性往往没有使用函数的好内联函数为了协调好效率和可读性之间的矛盾,C++提供了另一种方法,即定义内联函数,方法是在定义函数时用修饰词inline。内联函数inlineboolIsNum(charch){return(ch>='0'&&ch<='9')?true:false;}intmain(){ charch; for(inti=0;i<10;++i) { cin>>ch; if(IsNum(ch)==true) {++count;} } return0;}(ch>='0'&&ch<='9')?true:false内联函数函数体内含有循环、switch分支或复杂嵌套的if语句时,虽然能被定义为内联函数,但可能起不到内联函数的作用。内联函数实际上是一种用空间换时间的方案,使用内联函数节省了程序运行的时间开销,但是增加了代码占用内存的空间开销。因此在决定是否要使用内联函数时应权衡时间开销与空间开销的矛盾。5.9带有默认参数的函数带有默认参数的函数含义C++允许在函数声明或函数定义中为参数预赋默认值,这样的函数就叫做带有默认参数的函数。例doublefunc(doublex,doubley,intn=1000)如果函数调用时为相应参数指定了参数值,则参数将使用该值;否则参数使用其默认值。a=func(1.1,2.2);a=func(1.1,2.2,2000);带有默认参数的函数注意默认参数的设置应从参数表的最右边开始设置,从右到左依次设置。voidfunc(inta,intb=1,intc,intd=2);//error带有默认参数的函数注意默认参数的声明必须出现在函数调用之前。也就是说,如果存在函数原型,则参数的默认值应放在函数原型中指定。voidfunc(inta,intb,intc,intd); intmain() {func(1,2);return0;} voidfunc(inta,intb=1,intc=3,intd=2) {…}voidfunc(inta,intb=1,intc=3,intd=2);voidfunc(inta,intb,intc,intd){…}带有默认参数的函数注意如果函数原型中已给出了参数的默认值,则在函数定义中不得重复指定默认值,即使所指定的默认值完全相同也不行,否则编译出错。voidfunc(inta,intb=1,intc=3,intd=2); intmain() {func(1,2);return0; } voidfunc(inta,intb=1,intc=3,intd=2) {…}错误调试技术StepInto(快捷键:F11):跟踪StepOver(快捷键F10):单步执行StepOut(快捷键:Shift+F11):从函数体内运行到外RunToCursor(快捷键:Ctrl+F10):从当前位置运行到编辑光标观察窗口(Watch)用于观察指定变量或表达式的值intsum(inta,intb){ returna+b;}intmain(){ intt; t=100; t=sum(1,2); intb[2]; b[0]=10; b[1]=20; return0;}函数重载(overloading)函数重载即一组参数不同的函数共用一个函数名。调用函数时,由编译程序根据实参来选择调用哪个函数。自动变量auto和静态变量static#include<iostream>usingnamespacestd;intfunc(){ staticintcount=0; return++count;}intmain(){ for(inti=0;i<10;i++) cout<<func()<<"\t"; cout<<endl; return0;}输出结果:12345678910变量使用小结最常用的变量形式是局部变量。一般的局部变量都是自动变量,其作用域为定义局部变量的函数或分程序,生存期为程序执行到变量定义域中的期间。可以通过在说明语句前面加上保留字“static”将局部变量说明为静态局部变量。其作用域仍为定义局部变量的函数或分程序,但其生存期扩大到整个程序的运行期,其主要用途是保存函数的执行信息。声明于所有函数之外的变量称为全局变量,全局变量都是静态的,即具有和程序执行期相同的生存期。全局变量的作用域也可以扩充到其他源程序中。程序设计举例例6-7打印1000~10000之间的回文数。例6-8编写一个用于字符串比较的函数。例6-9利用高斯消去法解n元一次方程组。例6-10定义一个结构体矩形Rectangle,根据给出矩形的左上角顶点坐标和一个右下角顶点坐标,计算该矩形的面积。例6.7打印1000~10000之间的回文数回文数是指其各位数字左右对称的整数,例如12321、789987、1等都是十进制回文数。

算法:判断一个数是否回文,可以用除以10取余的方法,从最低位开始,依次取出该数的各位数字,然后用最低位充从当最高位,按反序从新构造新的数,比较与原数是否相等,若相等,则原数是回文数。//Example6-7:打印回文数#include<iostream.h>intIspalindrome(intn);intmain(){ for(inti=1000;i<10000;i++) { if(Ispalindrome(i)) cout<<i<<"\t"; } cout<<endl; return0;}intIspalindrome(intn){ intk,m=0; k=n; while(k) { m=m*10+k%10; k=k/10; } return(m==n);}例6.8编写一个用于字符串比较的函数算法字符串的比较应按字典序判断。例

温馨提示

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

评论

0/150

提交评论