第三章-函数-C++程序设计-计算机等级考试教学课件_第1页
第三章-函数-C++程序设计-计算机等级考试教学课件_第2页
第三章-函数-C++程序设计-计算机等级考试教学课件_第3页
第三章-函数-C++程序设计-计算机等级考试教学课件_第4页
第三章-函数-C++程序设计-计算机等级考试教学课件_第5页
已阅读5页,还剩159页未读 继续免费阅读

下载本文档

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

文档简介

第三章函数C++程序设计12/11/20221网络与计算中心基础教研室网络与计算中心基础教研室第三章函数C++程序设计12/1本章内容在结构化程序设计中,函数是将任务进行模块划分的基本单位。一个函数实现一项功能。在面向对象程序设计中,函数是对数据的一项操作,也是实现一项功能。12/11/20222网络与计算中心基础教研室本章内容在结构化程序设计中,函数是将任务进行模块划分的基本单3.1函数的定义与调用

3.5作用域与标识符的可见性

3.4函数调用机制

3.3全局变量和局部变量

3.2函数的参数传递,返回值及函数声明

3.9头文件与多文件结构3.6存储类型与标识符的生命期3.8函数的一些高级议题

3.7函数的递归调用

本章内容12/11/20223网络与计算中心基础教研室3.1函数的定义与调用3.5作用域与标识符的可见性3.1函数的定义与调用3.1.1函数概述3.1.2函数定义3.1.3函数调用12/11/20224网络与计算中心基础教研室3.1函数的定义与调用3.1.1函数概述12/11/函数是C++程序的基本组成模块。通过函数,可以把一个复杂任务分解成为若干个易于解决的小任务。充分体现逐步细化的设计思想。组成C++程序的若干函数中,有一个称为main()(Winmain())函数,是程序执行的入口,它可以调用其他函数,但不可以被调用。而其他一般函数既可以调用也可以被调用。函数概念的引入:入口函数:3.1.1函数概述12/11/20225网络与计算中心基础教研室函数是C++程序的基本组成模块。通过函数,可以把一个复杂任务图3.1函数调用层次关系main()fun2()fun1()fun3()funa()funb()func()3.1.1函数概述程序执行的入口12/11/20226网络与计算中心基础教研室图3.1函数调用层次关系main()fun2()f3.1.1函数概述

库函数和自定义函数:库函数或标准函数,是由编译系统预定义的,如一些常用的数学计算函数、字符串处理函数、图形处理函数、标准输入输出函数等。库函数都按功能分类,集中说明在不同的头文件中。用户只需在自己的程序中包含某个头文件,就可直接使用该文件中定义的函数。用户根据需要将某个具有相对独立功能的程序定义为函数,称自定义函数。12/11/20227网络与计算中心基础教研室3.1.1函数概述库函数和自定义函数:12/11/202函数头函数体数据类型函数名(形式参数表){ 语句序列}定义函数返回值的数据类型。若无返回值,void函数返回值由return语句给出3.1.2函数的定义函数运行时需要的数据,由主调函数提供。若无,void或者省略函数体可以为空,称为空函数。

12/11/20228网络与计算中心基础教研室函数头函数体数据类型函数名(形式参数表){定义3.1.2函数的定义无参函数//打印一个表头voidTableHead(){ cout<<″****************″<<endl; cout<<″*example*″<<endl; cout<<″****************″<<endl;}函数头intinput(){ //输入满足要求的数据

intn; cout<<″输入一个大于5的整数:″<<endl;

do cin>>n;

while(n<=5);

returnn;}函数数据类型=返回值数据类型12/11/20229网络与计算中心基础教研室3.1.2函数的定义无参函数//打印一个表头函数头i说明:

数据类型指函数返回值类型,可以是任一种数据类型,默认为返回整型值(但新标准要求写明,不用默认方式)。没有返回值应将返回值类型定义为void。函数名采用合法标识符表示。对无参函数,参数括号中的void通常省略,但括号不能省略。函数体由一系列语句组成。函数体可以为空,称为空函数。无参函数数据类型函数名(void) {函数体}3.1.2函数的定义12/11/202210网络与计算中心基础教研室说明:无参函数数据类型函数名(void)3//返回两个整数中的较大值

intmax(inta,intb){return(a>=b?a:b);}有参函数的参数表中列出所有形式参数的类型和参数名称。各参数即使类型相同也必须分别加以说明。

形式参数简称形参,只能是变量名,不允许是常量或表达式。voiddelay(longn){inti;

for(i=0;i<n;i++);}

//延时一段时间数据类型函数名(参数类型1形式参数1,参数类型2形式参数2,…) {函数体}有参函数3.1.2函数的定义12/11/202211网络与计算中心基础教研室//返回两个整数中的较大值有参函数的参数表中列出所问题:定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义在函数体内?原则:函数在使用时被看成“黑匣子”,除了输入输出外,其他部分可不必关心。从函数的定义看出,函数头正是用来反映函数的功能和使用接口,它所定义的是“做什么”。即明确了“黑匣子”的输入输出部分,输出就是函数的返回值,输入就是参数。因此,只有那些功能上起自变量作用的变量才必须作为参数定义在参数表中;函数体中具体描述“如何做”,因此除参数之外的为实现算法所需用的变量应当定义在函数体内。

C++中不允许函数的嵌套定义,即不允许在一个函数中定义另一个函数。提示12/11/202212网络与计算中心基础教研室问题:定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义3.1.3函数的调用函数调用所谓函数调用,就是使程序转去执行函数体。无参函数的调用格式:函数名()有参函数的调用格式:函数名(实际参数表)实际参数简称实参,用来将实际参数的值传递给形参,因此可以是常量、具有值的变量或表达式。在C++中,除了主函数外,其他任何函数都不能单独作为程序运行。任何函数功能的实现都是通过被主函数直接或间接调用进行的。12/11/202213网络与计算中心基础教研室3.1.3函数的调用函数调用无参函数的调用格式:【例3.1】输入两个实数,输出其中较大的数。其中求两个实数中的较大数用函数完成。程序如下:#include<iostream>usingnamespacestd;floatmax(floata,floatb){

return(a>=b?a:b);}intmain(){floatx,y;cout<<"输入两个实数:"<<endl;cin>>x>>y;cout<<x<<"和"<<y<<"中较大数为"<<max(x,y)<<endl;return0;}main()函数调用max(2.5,4.7)函数max(2.5,4.7)return4.7

主程序后续语句12/11/202214网络与计算中心基础教研室【例3.1】输入两个实数,输出其中较大的数。其中求两个实数3.2函数的参数传递、返回值及

函数声明3.2.1函数的参数传递及传值调用3.2.2函数返回值

3.2.3函数声明12/11/202215网络与计算中心基础教研室3.2函数的参数传递、返回值及

函数声明3.2.1函

3.2.1函数的参数传递及传值调用

传值调用和引用调用:按照参数形式的不同,C++有两种调用方式:传值调用和引用调用。传值调用传递的是实参的值,本章介绍传值调用12/11/202216网络与计算中心基础教研室3.2.1函数的参数传递及传值调用传值调用和引用调用:3.2.1函数的参数传递及传值调用

注意:【例1.3】中调用函数strcpy(s3,s2),却实现了字符数组s2[]的内容复制到字符数组s3[]中。这是因为数组名实际上代表存储数组的内存的首地址,复制给形参的是实参数组的首地址,结果参加运算的是实参数组。数组作为参数,定义时形参用数组名加一对方括号,调用时实参只用数组名传值调用:将实参的值复制给形参,在函数中参加运算的是形参,而实参不会发生任何改变。传值调用起了一种隔离作用。12/11/202217网络与计算中心基础教研室3.2.1函数的参数传递及传值调用注意:【例1.3】中【例3.2】实参和形参对应关系的示例。调用power(4.6,3)函数power(4.6,3)return97.336

主程序后续语句n=3x=4.6c=‘a’floatpower(floatx,intn){//求x的n次幂floatp=1;while(n--)p*=x;returnp;}intmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;return0;}12/11/202218网络与计算中心基础教研室【例3.2】实参和形参对应关系的示例。调用power(4.【例3.2】实参和形参对应关系的示例。调用power(‘a’,3)函数power(97,3)return912673

主程序后续语句n=3x=4.6c=‘a’floatpower(floatx,intn){//求x的n次幂floatp=1;while(n--)p*=x;returnp;}intmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;return0;}12/11/202219网络与计算中心基础教研室【例3.2】实参和形参对应关系的示例。调用power(‘a【例3.2】实参和形参对应关系的示例。调用power(3,4.6)函数power(3,4)return81主程序后续语句n=3x=4.6c=‘a’floatpower(floatx,intn){//求x的n次幂floatp=1;while(n--)p*=x;returnp;}intmain(){intn=3;floatx=4.6;charc='a';cout<<"power("<<x<<','<<n<<")="<<power(x,n)<<endl;cout<<"power("<<c<<','<<n<<")="<<power(c,n)<<endl;cout<<"power("<<n<<','<<x<<")="<<power(n,x)<<endl;return0;}12/11/202220网络与计算中心基础教研室【例3.2】实参和形参对应关系的示例。调用power(3,3.2.2函数返回值return语句的作用:

返回函数值

不再执行后续语句,程序控制返回调用点一个函数体内可以有多个return语句

表达式返回值的类型与函数类型不相同时,自动强制转换成函数的类型

return语句的格式:return

表达式;【例3.3】设计函数,根据三角形的三边长求面积。如果不能构成三角形,给出提示信息。分析:函数为计算三角形面积,一般三角形返回面积值,若不能构成三角形则返回-1。设计一个主函数完成函数测试。根据返回值情况输出相应结果。12/11/202221网络与计算中心基础教研室3.2.2函数返回值return语句的作用:retu【例3.3】程序:float

TriangleArea(floata,floatb,floatc){

if((a+b<=c)||(a+c<=b)||(b+c<=a))return-1;

floats;s=(a+b+c)/2;

returnsqrt(s*(s-a)*(s-b)*(s-c))

;}intmain(){

floata,b,c,area;cout<<"输入三角形三边a,b,c:"<<endl;cin>>a>>b>>c;

area=TriangleArea(a,b,c);

if(area==-1)cout<<'('<<a<<','<<b<<','<<c<<')'<<"不能构成三角形!"<<endl;

else cout<<"三角形("<<a<<','<<b<<','<<c<<")面积为:"<<area<<endl;

return0;}3.2.2函数返回值12/11/202222网络与计算中心基础教研室【例3.3】程序:floatTriangleArea(fl讨论:-函数可以有返回值,也可以没有返回值。对于没有返回值的函数,功能只是完成一定操作,应将返回值类型定义为void,函数体内可以没有return语句,当需要在程序指定位置退出时,可以在该处放置一个:return;3.2.2结束返回值是如何返回到调用处的?实际上,在函数返回时,系统会在内存建立一个临时变量,函数返回时将函数值保存在该临时变量中,然后由主调函数中包含调用的表达式语句从该临时变量中取得值,表达式语句执行后该临时变量撤销。

3.2.2函数返回值12/11/202223网络与计算中心基础教研室讨论:3.2.2结束返回值是如何返回到调用处的?3.2.23.2.3

函数声明语法上对程序文件中函数的排列次序要求满足先定义后使用。对于函数,只要在调用之前作函数声明(FunctionDeclaration),则函数定义放在任何位置程序都能正确编译运行。

函数声明的引入:函数声明的格式:

函数声明是一条以分号结束的语句:

数据类型函数名(形式参数表);

12/11/202224网络与计算中心基础教研室3.2.3函数声明语法上对程序文件中函数的排列次序要例如【例3.3】中求三角形面积的函数声明为:floatTriangleArea(floata,floatb,floatc);或floatTriangleArea(float,float,float);但下面的函数原型是错误的:intTriangleArea(float,float,float); //错误,返回值类型不同floatTriangleArea(int,int,int);//错误,参数类型不同floatTriangleArea(float,float); //错误,参数个数不同float

TriangleArea(floata,floatb,floatc){

if((a+b<=c)||(a+c<=b)||(b+c<=a))return-1;

floats;s=(a+b+c)/2;

returnsqrt(s*(s-a)*(s-b)*(s-c))

;}12/11/202225网络与计算中心基础教研室例如【例3.3】中求三角形面积的函数声明为:floatTr

下面是一个使用结构化程序设计思想开发的企业管理报表程序的框架。它使用了函数声明。voidmenu_print();voidaccount_report();voidengineering_report();voidmarketing_report();intmain(){

intchoice;

do{

menu_print(); cin>>choice;}while(choice<=0||choice>=4);

switch(choice){

case1:account_report();break;

case2:engineering_report();break;

case3:marketing_report();break;}

return0;}12/11/202226网络与计算中心基础教研室下面是一个使用结构化程序设计思想开发的企业管理报表voidmenu_print(){cout<<”系统功能:”<<endl;cout<<”1 财务报表”<<endl;cout<<”2 工程报表”<<endl;cout<<”3 市场报表”<<endl;cout<<”选择业务序号:”;}voidaccount_report(){

//生成财务报表}voidengineering_report(){

//生成工程报表

}voidmarketing_report(){

//生成市场报表;}12/11/202227网络与计算中心基础教研室voidmenu_print(){12/11/202223.2.3

函数声明【例3.4】

输出所有满足下列条件的正整数m:10<m<1000且m、m2、m3均为回文数。分析:回文指左右对称的序列。如121、353等就是回文数。判断整数是否回文数用函数实现,其思想是将该数各位拆开后反向组成新的整数,如果该整数与原数相等则为回文数。mm*mm*m*m111211331101102011030301111123211367631

运行结果:12/11/202228网络与计算中心基础教研室3.2.3函数声明【例3.4】输出所有满足下列条件boolpalindrome(int);

//函数声明intmain(){

intm; cout<<setw(10)<<'m'<<setw(20)<<"m*m“ <<setw(20)<<"m*m*m"<<endl;

for(m=11;m<1000;m++)

if(palindrome(m)&&palindrome(m*m) &&palindrome(m*m*m))

cout<<setw(10)<<m<<setw(20)<<m*m <<setw(20)<<m*m*<<endl;

return0;}【例3.4】输出回文数12/11/202229网络与计算中心基础教研室boolpalindrome(int);//函数声明【例boolpalindrome(int

n){

//判断回文数

intdigit[10];

intm=n,i=0,j;

do{ digit[i]=n%10;n/=10;i++; }while(n>0);

for(j=0;j<i;j++)n=n*10+digit[j];

return(n==m);}【例3.4】输出回文数12/11/202230网络与计算中心基础教研室boolpalindrome(intn){ //判断回文3.3全局变量和局部变量3.3.1变量的存储机制与C++的内存布局3.3.2全局变量3.3.3局部变量12/11/202231网络与计算中心基础教研室3.3全局变量和局部变量3.3.1变量的存储机制与C3.3.1变量的存储机制与C++的内存布局自由存储区(动态数据)

操作系统为一个C++程序的运行所分配的内存分为四个区域,如图3.3

所示:栈区(函数局部数据)全局数据区(全局、静态)代码区(程序代码)(main()函数局部数据)自由存储区(动态数据)12/11/202232网络与计算中心基础教研室3.3.1变量的存储机制与C++的内存布局自由存储区(动存储区域说明:(1)代码区(Codearea):存放程序代码,即程序中各个函数的代码块;(2)全局数据区(Dataarea):存放全局数据和静态数据;分配该区时内存全部清零,结果变量的所有字节等效初始化为全0。(3)栈区(Stackarea):存放局部变量,如函数中的变量等;分配栈区时不处理内存,即变量取随机值。(4)自由存储区(Freestorearea):存放与指针相关的动态数据。分配自由存储区时不处理内存。参见第七章。3.3.1变量的存储机制与C++的内存布局12/11/202233网络与计算中心基础教研室存储区域说明:3.3.1变量的存储机制与C++的内存布局13.3.2全局变量在所有函数之外定义的变量称为全局变量。全局变量存放在全局数据区,因编译器自动将该区清为全0,如果用户在定义时不显式给出初始化值,则等效初始化为全0。全局变量可定义在程序开头,也可定义在中间位置,该全局变量在定义处之后的任何位置都是可以访问的,称为可见的。全局变量引入:12/11/202234网络与计算中心基础教研室3.3.2全局变量在所有函数之外定义的变量称为全局打印200调用func()函数func()200*2=400打印400n=100n=100*2=200【例3.5】多个函数使用全局变量的例子。intn=100;voidfunc(){ n*=2;}intmain(){ n*=2; cout<<n<<endl; func(); cout<<n<<endl;

return0;}12/11/202235网络与计算中心基础教研室打印调用函数200*2打印n=100n=100*2【例3.53.3.3局部变量

定义在函数内或块内的变量称为局部变量。程序中使用的绝大多数变量都是局部变量。局部变量在程序运行到它所在的块时建立在栈中,该块执行完毕局部变量占有的空间即被释放。故亦称为自动变量。局部变量在定义时可加修饰词auto,但通常省略。局部变量在定义时若未初始化,其值为随机数。局部变量引入:12/11/202236网络与计算中心基础教研室3.3.3局部变量定义在函数内或块内的变量称为局部打印main()中的t=3.5调用fun()函数fun()打印fun()中的t=5

打印main()中的t=3.5t=3.5t=5voidfun(){auto

int

t=5;//fun()中的局部变量,auto可省略cout<<"fun()中的t="<<t<<endl;}intmain(){float

t=3.5;//main()函数中的局部变量cout<<"main()中的t="<<t<<endl;fun();cout<<"main()中的t="<<t<<endl;return0;}【例3.6】使用局部变量的例子。12/11/202237网络与计算中心基础教研室打印main()中的t=3.5调用函数打印fun()中的t=3.4函数调用机制局部变量占用的内存是在程序执行过程中“动态”地建立和释放的12/11/202238网络与计算中心基础教研室3.4函数调用机制局部变量占用的内存是在程序执行过程中“局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。函数调用机制

函数调用过程:(1)建立栈空间;(2)保护现场:主调函数运行状态和返回地址入栈;(3)为被调函数中的局部变量分配空间,完成参数传递;(4)执行被调函数函数体;(5)释放被调函数中局部变量占用的栈空间;(6)恢复现场:取主调函数运行状态及返回地址,释放栈空间;(7)继续主调函数后续语句。12/11/202239网络与计算中心基础教研室局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。voidfun1(int,int);voidfun2(float);intmain(){intx=1;y=2;fun1(x,y);

returno;}voidfun1(inta,intb){

floatx=3;fun2(x);}voidfun2(floaty){

intx;…}x栈顶栈底y3fun2()fun1()运行状态及返回地址x3b2a1fun1()main()运行状态及返回地址y2x1main()操作系统运行状态及返回地址3.4函数调用机制

此图例说明在程序执行过程中怎样通过栈“动态”地建立和释放局部变量占用的内存的12/11/202240网络与计算中心基础教研室voidfun1(int,int);x栈顶y3fun2(3.5作用域与标识符的可见性3.5.1块域3.5.2函数声明域3.5.3文件域12/11/202241网络与计算中心基础教研室3.5作用域与标识符的可见性3.5.1块域12/11

作用域:指标识符能够被使用的范围。只有在作用域内标识符才可以被访问(称为可见)。本节重点讨论局部域和文件域(全局域),其中局部域包括块域和函数声明域。任何标识符作用域的起始点均为标识符说明处。作用域与标识符的可见性12/11/202242网络与计算中心基础教研室作用域:指标识符能够被使用的范围。只有在作用域内标识符才可函数中定义的标识符,包括形参和函数体中定义的局部变量,作用域都在该函数内,也称作函数域。块指一对大括号括起来的程序段。块中定义的标识符,作用域在块内。复合语句是一个块。函数也是一个块。复合语句中定义的标识符,作用域仅在该复合语句中。块的引入:

3.5.1块域12/11/202243网络与计算中心基础教研室函数中定义的标识符,包括形参和函数体中定义的局a=3b=535a=3b=5a=5b=3【例3.7】输入两数,按从大到小的顺序保存,并输出结果。结果栈t=3intmain(){

inta,b; //具有函数域

cout<<"输入两整数:"<<endl;

cin>>a>>b;

cout<<“a="<<a<<'\t'<<"b="<<b<<endl;

if(b>=a){

intt;

//具有块域

t=a;

a=b;b=t;//交换a,b的值

}cout<<"a="<<a<<'\t'<<"b="<<b<<endl;

return0;}上述程序若在最后一个cout语句处增加:cout<<t<<endl;则编译时会提示错误,因为变量t的作用域只在if语句中,其它地方不可见。

3.5.1块域12/11/202244网络与计算中心基础教研室a=3b=535a=3b=5a=由VC++运行,结果如下:输入两整数:35调用前:实参a=3,b=5调用中…交换前:形参a=3,b=5交换后:形参a=5,b=3调用后:实参a=3,b=5

交换失败操作系统运行状态及返回地址main()3a5bmain()运行状态及返回地址swap()3a5b3t35

3.5.1块域局部变量具有局部作用域,使得程序在不同块中可以使用同名变量。这些同名变量各自在自己的作用域中可见,在其它地方不可见【例3.8】设计函数完成两数交换,用主函数进行测试。12/11/202245网络与计算中心基础教研室由VC++运行,结果如下:操作系统运行状态及返回地址main全局n=100200300内i=500内j=600内n=500+600=11001100500600100200+300=500500

500200300外部i=200外部j=300【例3.9】

显示同名变量可见性。intn=100;#include<iostream.h>intmain(){inti=200,j=300;cout<<n<<'\t'<<i<<'\t'<<j<<endl;{ //内部块

inti=500,j=600,n;n=i+j;cout<<n<<'\t'<<i<<'\t'<<j<<endl;

//输出局部变量ncout<<::n<<endl;//输出全局变量n}n=i+j; //修改全局变量cout<<n<<'\t'<<i<<'\t'<<j<<endl;return0;}12/11/202246网络与计算中心基础教研室全局n=100200300内i=

对于块中嵌套其它块的情况,如果嵌套块中有同名局部变量,服从局部优先原则,即在内层块中屏蔽外层块中的同名变量,换句话说,内层块中局部变量的作用域为内层块;外层块中局部变量的作用域为外层除去包含同名变量的内层块部分。如果块内定义的局部变量与全局变量同名,块内仍然局部变量优先,但与块作用域不同的是,在块内可以通过域运算符“::”访问同名的全局变量。

3.5.1块域12/11/202247网络与计算中心基础教研室对于块中嵌套其它块的情况,如果嵌套块中有同名

函数声明不是定义函数,在作函数声明时,其中的形参作用域只在声明中,即作用域结束于右括号。正是由于形参不能被程序的其他地方引用,所以通常只要声明形参个数和类型,形参名可省略。3.5.2函数声明域

12/11/202248网络与计算中心基础教研室函数声明不是定义函数,在作函数声明时,其中的形参作3.5.3文件域文件域也称全局域。定义在所有函数之外的标识符作用域为从定义处到整个源文件结束,即文件域。文件中定义的全局变量和函数的作用域为文件域。12/11/202249网络与计算中心基础教研室3.5.3文件域文件域也称全局域。定义在所有函数之外的标识3.6存储类型与标识符的生命期

3.6.1存储类型3.6.2生命期12/11/202250网络与计算中心基础教研室3.6存储类型与标识符的生命期3.6.1存储类型123.6存储类型与标识符的生命期

存储类型(storageclass)决定标识符的存储区域,即编译系统在不同区域为不同存储类型的标识符分配空间。由于存储区域不同,标识符的生命期也不同。所谓生命期,指的是标识符从获得空间到空间释放之间的期间,标识符只有在生存期中、并且在其自己的作用域中才能被访问。12/11/202251网络与计算中心基础教研室3.6存储类型与标识符的生命期存储类型(storag用auto和register修饰的称为自动存储类型用static修饰的称为静态存储类型用extern修饰的称为外部存储类型。3.6.1存储类型

存储类型的说明符(storageclassspecifier)autoregisterstaticextern12/11/202252网络与计算中心基础教研室用auto和register修饰的称为自动存储类型3.6.1自动存储类型自动变量为用auto说明的变量,通常auto缺省。局部变量都是自动变量,生命期开始于块的执行,结束于块的结束,其原因是自动变量的空间分配在栈中,块开始执行时系统自动分配空间,块执行结束时系统自动释放空间。故自动变量的生命期和作用域是一致的。3.6.1存储类型

为提高程序运行效率,可以将某些变量保存在寄存器中,即用register说明为寄存器变量,但不提倡使用。12/11/202253网络与计算中心基础教研室自动存储类型3.6.1存储类型为提高程序运行效率,可3.6.1存储类型

静态存储类型static说明的变量称为静态变量。位置不同区别局部静态变量和全局静态变量,也称内部静态变量和外部静态变量。静态变量均存储在全局数据区,如果程序未显式给出初始化值,则等效初始化为全0。静态变量占有的空间要到整个程序执行结束才释放,故静态变量具有整个程序执行期间的生命期。12/11/202254网络与计算中心基础教研室3.6.1存储类型静态存储类型12/11/20225局部静态变量是定义在块中的静态变量,编译系统在全局数据区为其开辟空间并保存数据,如果显式给出初始化值,则在该块第一次执行时完成,且只进行一次。【例3.10】自动变量与局部静态变量的区别3.6.1存储类型

12/11/202255网络与计算中心基础教研室局部静态变量是定义在块中的静态变量,编译系统在全局数据区为其【例3.10】自动变量与局部静态变量的区别intst(){

staticintt=100;//局部静态变量t++;returnt;}intat(){

intt=100;//自动变量t++;returnt;}intmain(){

inti;

for(i=0;i<5;i++)cout<<at()<<'\t';cout<<endl;

for(i=0;i<5;i++)cout<<st()<<'\t';cout<<endl;

return0;}i=0t=100123451011011011011013.6.1存储类型

12/11/202256网络与计算中心基础教研室【例3.10】自动变量与局部静态变量的区别intst(i=0t=10012101345102103104105【例3.10】自动变量与局部静态变量的区别intst(){

staticintt=100;//局部静态变量t++;returnt;}intat(){

intt=100;//自动变量t++;returnt;}intmain(){

inti;

for(i=0;i<5;i++)cout<<at()<<‘=\t';cout<<endl;

for(i=0;i<5;i++)cout<<st()<<'\t';cout<<endl;

return0;}3.6.1存储类型

12/11/202257网络与计算中心基础教研室i=0t=100121013451021031041053.6.2生命期静态生命期静态生命期(Staticextent或Staticstorageduration)指的是标识符从程序开始运行时就存在,具有存储空间,到程序运行结束时消亡,释放存储空间。具有静态生命期的标识符存放在全局数据区,如全局变量、静态全局变量、静态局部变量。具有静态生命期的标识符在未被用户初始化的情况下,系统会等效将其初始化为全0。函数驻留在代码区,也具有静态生命期。所有具有文件作用域的标识符都具有静态生命期12/11/202258网络与计算中心基础教研室3.6.2生命期静态生命期12/11/202258网络与计3.6.2

生命期

局部生命期在函数内部或块中定义的标识符具有局部生命期(Automaticextent或Automaticstorageduration),其生命期开始于执行到该函数或块的标识符定义处,结束于该函数或块的结束处。具有局部生命期的标识符存放在栈区。具有局部生命期的标识符如果未被初始化,其内容是随机的,不可引用。具有局部生命期的标识符必定具有局部作用域;但反之不然,静态局部变量具有局部作用域,但却具有静态生命期。12/11/202259网络与计算中心基础教研室3.6.2生命期局部生命期12/11/23.6.2

生命期动态生命期具有动态生命期(dynamicextent或dynamicstorageduration)的标识符存放在自由存储区,由特定的函数调用或运算来创建和释放如用new运算符(或调用malloc()函数)为变量分配存储空间时,变量的生命期开始而用delete运算符(或调用free()函数)释放空间或程序结束时,变量生命期结束。关于new运算符和delete运算符将在第七章中介绍12/11/202260网络与计算中心基础教研室3.6.2生命期动态生命期12/11/202260网络与计3.7函数的递归调用

自己调用自己12/11/202261网络与计算中心基础教研室3.7函数的递归调用自己调用自己12/11/20226可以看出是用阶乘定义阶乘,这种自己定义自己的方法称为递归定义。递归的引入

递归是一种描述问题的方法,或称算法。递归的思想可以简单地描述为“自己调用自己”。例如用如下方法定义阶乘:12/11/202262网络与计算中心基础教研室可以看出是用阶乘定义阶乘,这种自己定义自己的方法称为递归定义递归定义的阶乘函数:fac(intn){inty;if(n==0||n==1)y=1;elsey=n*fac(n-1);returny;}只要设计主函数调用阶乘函数,即可实现计算阶乘。递归的引入递归函数必须定义递归终止条件(Stoppingcondition),避免无穷递归(InfiniteRecursion)。12/11/202263网络与计算中心基础教研室递归定义的阶乘函数:递归的引入递归函数必须定义递归终止条件(#include<iostream.h>intfac(intn){

inty;cout<<n<<'\t';

if(n==0||n==1)y=1;elsey=n*fac(n-1); cout<<y<<'\t';

returny;}intmain(){ cout<<"\n4!="<<fac(4)<<endl;

returno;}n=4cout<<4;y=4*fac(3);fac(4)=cout<<2;y=2*fac(1);

n=2cout<<1;y=1;cout<<1;return1;

n=1n=3cout<<3;y=3*fac(2);cout<<24;return24;cout<<6;return6;cout<<2;return2;24递归的引入【例3.12】求4!12/11/202264网络与计算中心基础教研室#include<iostream.h>n=4cout<递归过程分析递归函数的执行分为“递推”和“回归”两个过程这两个过程由递归终止条件控制,即逐层递推,直至递归终止条件,然后逐层回归。每次调用发生时都首先判断递归终止条件12/11/202265网络与计算中心基础教研室递归过程分析递归函数的执行分为“递推”和“回归”两个过程12注意:右图中存“fac(1)返回值”等的存储单元是无名临时局部变量,其生命期在表达式y=n*fac(n-1)中。因为被调函数的返回语句格式为:return表达式;为返回表达式的值,必须有一个无名临时局部变量来承载这个值。然后由主调函数中包含调用的表达式语句从该临时变量中取得值,表达式语句执行后该临时变量撤销。

递归过程分析现场与返回地址第一层fac(4)域4n4*6→24y现场与返回地址第二层fac(3)域3n3*2→6y现场与返回地址第三层fac(2)域2n2*1→2y现场与返回地址第四层fac(1)域ny11存fac(1)返回值存fac(2)返回值存fac(3)返回值126fac(4)返回值=24main()域存fac(4)返回值2412/11/202266网络与计算中心基础教研室注意:递归过程分析现场与返回地址第一层fac(4)域4n4*3.8函数的一些高级议题

3.8.1函数重载3.8.2默认参数3.8.3内联函数12/11/202267网络与计算中心基础教研室3.8函数的一些高级议题3.8.1函数重载12/13.8.1函数重载

3.8.1函数重载

重载的引入C++中,如果需要定义几个功能相似,而参数类型不同的函数,那么这样的几个函数可以使用相同的函数名,这就是函数重载例:求和函数对应不同的参数类型可以定义如下几个重载函数:intsum(inta,intb)doublesum(doublea,doubleb)floatsum(floata,floatb,floatc)12/11/202268网络与计算中心基础教研室3.8.1函数重载3.8.1函数重载重载的引因此在定义重载函数时必须保证参数类型不同,仅仅返回值类型不同是不行的。函数重载的好处在于,可以用相同的函数名来定义一组功能相同或类似的函数,程序的可读性增强。3.8.1函数重载

重载匹配规则(1)如果有严格匹配的函数,就调用该函数;(2)参数内部转换后如果匹配,调用该函数;(3)通过用户定义的转换寻求匹配。12/11/202269网络与计算中心基础教研室因此在定义重载函数时必须保证参数类型不同,仅仅返回值类型不同3.8.1函数重载

3+5=调用sum(3,5)函数sum(3,5)return82.2+5.6=调用sum(2.2,5.6)函数doublesum(2.2,5.6)return7.83.5+4+8=调用sum(3.5,4,8)函数floatsum(3.5,4.0,8.0)return15.5结束87.815.5intsum(inta,intb){

returna+b;}Doublesum(doublea,doubleb){

returna+b;}floatsum(floata,floatb,floatc){

returna+b+c;}intmain(){ cout<<"3+5="<<sum(3,5) <<endl; cout<<"2.2+5.6=" <<sum(2.2,5.6)<<endl; cout<<"3.5+4+8=" <<sum(3.5,4,8)<<endl;

return0;}【例3.16】重载函数的应用。12/11/202270网络与计算中心基础教研室3.8.1函数重载3+5=调用函数sum(3,5)3.8.2默认参数

默认参数的引入默认参数指在定义函数时为形参指定默认值(缺省值)。这样的函数在调用时,对于默认参数,可以给出实参值,也可以不给出参数值。如果给出实参,将实参传递给形参进行调用,如果不给出实参,则按默认值进行调用12/11/202271网络与计算中心基础教研室3.8.2默认参数默认参数的引入12/11/2022voiddelay(intloops=5){//延时函数,默认延时5个时间单位

for(;loops>0;loops--);}intmain(){ delay(3); cout<<"延时3个时间单位"<<endl; delay(); //等同于delay(5) cout<<"延时5个时间单位"<<endl;

return0;}123延时3个时间单位12345延时5个时间单位3.8.2默认参数

【例3.17】默认参数12/11/202272网络与计算中心基础教研室voiddelay(intloops=5){123延时3使用要点:默认参数可以有多个,但所有默认参数必须放在参数表的右侧,即先定义所有的非默认参数,再定义默认参数。这是因为在函数调用时,参数自左向右逐个匹配,当实参和形参个数不一致时只有这样才不会产生二义性。在同一个作用域中一个参数只能被指定一次默认值,不可以在声明和定义中同时指定默认值,即使默认值一样也不行。3.8.2默认参数

12/11/202273网络与计算中心基础教研室使用要点:3.8.2默认参数12/11/20227intfun2(int,int=10,int=20); //函数声明中给出缺省值。参数名也可省略voidfun1(){…}intfun2(inta,intb,intc){…}//定义中不再给出缺省值习惯上,缺省参数在公共头文件包含的函数声明中指定,否则缺省实参只能用于包含该函数定义的文件中的函数调用。3.8.2默认参数

12/11/202274网络与计算中心基础教研室intfun2(int,int=10,int=23.8.3内联函数

内联函数的引入:为了协调好效率和可读性之间的矛盾,C++提供了另一种方法,即定义内联函数,方法是在定义函数时用修饰词inline。12/11/202275网络与计算中心基础教研室3.8.3内联函数内联函数的引入:12/11/2023.8.3内联函数3.8.3内联函数

因使用频度很高,说明为内联函数。请看如下程序段,读入一行字符串,逐个判断是否为数字字符:inline

intIsNumber(charch){

returnch>='0'&&ch<='9'?1:0;}intmain(){

charch;

while(cin.get(ch),ch!='\n'){

if(IsNumber(ch))cout<<"是数字字符"

<<endl;

elsecout<<"不是数字字符"

<<endl;}

return0;}12/11/202276网络与计算中心基础教研室3.8.3内联函数3.8.3内联函数因使用频3.8.3内联函数

内联函数的调用机制与一般函数不同,编译器在编译过程中遇到inline时,为该函数建立一段代码,而后在每次调用时直接将该段代码嵌入到调用函数中,从而将函数调用方式变为顺序执行方式,这一过程称为内联函数的扩展或内联。

因inline指示符对编译器而言只是一个建议,编译器也可以选择忽略该建议。3.8.3内联函数

12/11/202277网络与计算中心基础教研室3.8.3内联函数内联函数的调用机制3.9头文件与多文件结构

3.9.1头文件3.9.2多文件结构12/11/202278网络与计算中心基础教研室3.9头文件与多文件结构3.9.1头文件12/11/#include<iostream>usingnamespacestd;其中iostream是在标准名字空间域std中定义的头文件。对应的传统方式的文件名为<iostream.h>,头文件以“.h”为后缀3.9.1头文件标准库头文件考虑标识符在其他文件中的可见性,使用头文件是很有效的方法系统定义的头文件中定义了一些常用的公用标识符和函数,用户只要将头文件包含进自己的文件,就可使头文件中定义的标识符在用户文件中变得可见,也就可以直接使用头文件中定义的标识符和函数。

12/11/202279网络与计算中心基础教研室#include<iostream>3.9.1头文件标准:自定义头文件除了系统定义的头文件外,用户还可以自定义头文件。对于具有外部存储类型的标识符,可以在其他任何一个源程序文件中经声明后引用,因此用户完全可以将一些具有外部存储类型的标识符的声明放在一个头文件中。具体地说,头文件中可以包括:用户构造的数据类型(如枚举类型),外部变量,外部函数、常量和内联函数等具有一定通用性或常用的量,而一般性的变量和函数定义不宜放在头文件中。3.9.1头文件12/11/202280网络与计算中心基础教研室:自定义头文件3.9.1头文件12/11/20228在开发较大程序时,通常将其分解为多个源程序文件,每个较小的程序用一个源程序文件建立。程序经过建立、编译、连接,成为一个完整的可执行程序。多文件结构通过工程进行管理,在工程中建立若干用户定义的头文件.h和源程序文件.cpp。头文件中定义用户自定义的数据类型,所有的程序实现则放在不同的源程序文件中。编译时每个源程序文件单独编译,如果源程序文件中有编译预处理指令,则首先经过编译预处理生成临时文件存放在内存,之后对临时文件进行编译生成目标文件.obj,编译后临时文件撤销。所有的目标文件经连接器连接最终生成一个完整的可执行文件.exe。3.9.2多文件结构

12/11/202281网络与计算中心基础教研室在开发较大程序时,通常将其分解为多个源程序文件,每个较小的程编译

预编译编译

预编译

预编译编译file1.hfile1.cppfile2.hfile2.cppfilen.hfilen.cpp临时文件1临时文件2临时文件nfile1.objfile2.objfilen.objFilename.exe.libC++标准类库连接运行3.9.2多文件结构

图3.11C++程序开发过程12/11/202282网络与计算中心基础教研室编译预编译编译预编译预编译编译file1.hfile1第三章函数C++程序设计12/11/202283网络与计算中心基础教研室网络与计算中心基础教研室第三章函数C++程序设计12/1本章内容在结构化程序设计中,函数是将任务进行模块划分的基本单位。一个函数实现一项功能。在面向对象程序设计中,函数是对数据的一项操作,也是实现一项功能。12/11/202284网络与计算中心基础教研室本章内容在结构化程序设计中,函数是将任务进行模块划分的基本单3.1函数的定义与调用

3.5作用域与标识符的可见性

3.4函数调用机制

3.3全局变量和局部变量

3.2函数的参数传递,返回值及函数声明

3.9头文件与多文件结构3.6存储类型与标识符的生命期3.8函数的一些高级议题

3.7函数的递归调用

本章内容12/11/202285网络与计算中心基础教研室3.1函数的定义与调用3.5作用域与标识符的可见性3.1函数的定义与调用3.1.1函数概述3.1.2函数定义3.1.3函数调用12/11/202286网络与计算中心基础教研室3.1函数的定义与调用3.1.1函数概述12/11/函数是C++程序的基本组成模块。通过函数,可以把一个复杂任务分解成为若干个易于解决的小任务。充分体现逐步细化的设计思想。组成C++程序的若干函数中,有一个称为main()(Winmain())函数,是程序执行的入口,它可以调用其他函数,但不可以被调用。而其他一般函数既可以调用也可以被调用。函数概念的引入:入口函数:3.1.1函数概述12/11/202287网络与计算中心基础教研室函数是C++程序的基本组成模块。通过函数,可以把一个复杂任务图3.1函数调用层次关系main()fun2()fun1()fun3()funa()funb()func()3.1.1函数概述程序执行的入口12/11/202288网络与计算中心基础教研室图3.1函数调用层次关系main()fun2()f3.1.1函数概述

库函数和自定义函数:库函数或标准函数,是由编译系统预定义的,如一些常用的数学计算函数、字符串处理函数、图形处理函数、标准输入输出函数等。库函数都按功能分类,集中说明在不同的头文件中。用户只需在自己的程序中包含某个头文件,就可直接使用该文件中定义的函数。用户根据需要将某个具有相对独立功能的程序定义为函数,称自定义函数。12/11/202289网络与计算中心基础教研室3.1.1函数概述库函数和自定义函数:12/11/202函数头函数体数据类型函数名(形式参数表){ 语句序列}定义函数返回值的数据类型。若无返回值,void函数返回值由return语句给出3.1.2函数的定义函数运行时需要的数据,由主调函数提供。若无,void或者省略函数体可以为空,称为空函数。

12/11/202290网络与计算中心基础教研室函数头函数体数据类型函数名(形式参数表){定义3.1.2函数的定义无参函数//打印一个表头voidTableHead(){ cout<<″****************″<<endl; cout<<″*example*″<<endl; cout<<″****************″<<endl;}函数头intinput(){ //输入满足要求的数据

intn; cout<<″输入一个大于5的整数:″<<endl;

do cin>>n;

while(n<=5);

returnn;}函数数据类型=返回值数据类型12/11/202291网络与计算中心基础教研室3.1.2函数的定义无参函数//打印一个表头函数头i说明:

数据类型指函数返回值类型,可以是任一种数据类型,默认为返回整型值(但新标准要求写明,不用默认方式)。没有返回值应将返回值类型定义为void。函数名采用合法标识符表示。对无参函数,参数括号中的void通常省略,但括号不能省略。函数体由一系列语句组成。函数体可以为空,称为空函数。无参函数数据类型函数名(void) {函数体}3.1.2函数的定义12/11/202292网络与计算中心基础教研室说明:无参函数数据类型函数名(void)3//返回两个整数中的较大值

intmax(inta,intb){return(a>=b?a:b);}有参函数的参数表中列出所有形式参数的类型和参数名称。各参数即使类型相同也必须分别加以说明。

形式参数简称形参,只能是变量名,不允许是常量或表达式。voiddelay(longn){inti;

for(i=0;i<n;i++);}

//延时一段时间数据类型函数名(参数类型1形式参数1,参数类型2形式参数2,…) {函数体}有参函数3.1.2函数的定义12/11/202293网络与计算中心基础教研室//返回两个整数中的较大值有参函数的参数表中列出所问题:定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义在函数体内?原则:函数在使用时被看成“黑匣子”,除了输入输出外,其他部分可不必关心。从函数的定义看出,函数头正是用来反映函数的功能和使用接口,它所定义的是“做什么”。即明确了“黑匣子”的输入输出部分,输出就是函数的返回值,输入就是参数。因此,只有那些功能上起自变量作用的变量才必须作为参数定义在参数表中;函数体中具体描述“如何做”,因此除参数之外的为实现算法所需用的变量应当定义在函数体内。

C++中不允许函数的嵌套定义,即不允许在一个函数中定义另一个函数。提示12/11/202294网络与计算中心基础教研室问题:定义函数时究竟哪些变量应当作为函数的参数?哪些应当定义3.1.3函数的调用函数调用所谓函数调用,就是使程序转去执行函数体。无参函数的调用格式:函数名()有参函数的调用格式:函数名(实际参数表)实际参数简称实参,用来将实际参数的值传递给形参,因此可以是常量、具有值的变量或表达式。在C++中,除了主函数外,其他任何函数都不能单独作为程序运行。任何函数功能的实现都是通过被主函数直接或间接调用进行的。12/11/202295网络与计算中心基础教研室3.1.3函数的调用函数调用无参函数的调用格式:【例3.1】输入两个实数,输出其中较大的数。其中求两个实数中的较大数用函数完成。程序如下:#include<iostream>usingnamespacestd;floatmax(floata,floatb){

return(a>=b?a:b);}intmain(){floatx,y;cout<<"输入两个实数:"<<endl;cin>>x>>y;cout<<x<<"和"<<y<<"中较大数为"<<max(x,y)<<endl;return0;}main()函数调用max(2.5,4.7)函数max(2.5,4.7)return4.7

主程序后续语句12/11/202296网络与计算中心基础教研室【例3.1】输入两个实数,输出其中较大的数。其中求两个实数3.2函数的参数传递、返回值及

函数声明3.2.1函数的参数传递及传值调用3.2.2函数返回值

3.2.3函数声明12/11/202297网络与计算中心基础教研室3.2函数的参数传递、返回值及

函数声明3.2.1函

3.2.1函数的参数传递及传值调用

传值调用和引用调用:按照参数形式的不同,C++有两种调用方式:传值调用和引用调用。传值调用传递的是实参的值,本章介绍传值调用12/11/202298网络与计算中心基础教研室3.2.1函数的参数传递及传值调用传值调用和引用调用:3.2.1函数的参数传递及传值调用

注意:【例1.3】中调用函数strcpy(s3,s2),却实现了字符数组s2[]的内容复制到字符数组s3[]中。这是因为数组名实际上代表存储数组的内存的首地址,复制给形参的是实参数组的首地址,结果参加运算的是实参数组。数组作为参数,定义时形参用数组名加一对方括号,调用时实参只用数组名传值调用:将实参的值复制给形参,在函数中参加运算的是形参,而实参不会发生任何改变。传值调用起了一种隔离作用。12/11/202299网络与计算中心基础教研室3.2.1函数的参数传递及传值调用注意:【例1.3】中【例3.2】实参和形参对应关系的示例。调用power(4.6,3)函数power(4.6,3)return97.336

主程序后续语句n=3x=4.6c=‘a’floatpower(floatx,intn){//求x的n次幂floatp=1;while(n--)p*=x;returnp;}intmain(){intn=3;floatx=4.6;charc='a';cout<<

温馨提示

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

评论

0/150

提交评论