![函数2省公开课一等奖全国示范课微课金奖_第1页](http://file4.renrendoc.com/view2/M00/2F/03/wKhkFmY3W5OAJ1mqAAEQM1j_i6U362.jpg)
![函数2省公开课一等奖全国示范课微课金奖_第2页](http://file4.renrendoc.com/view2/M00/2F/03/wKhkFmY3W5OAJ1mqAAEQM1j_i6U3622.jpg)
![函数2省公开课一等奖全国示范课微课金奖_第3页](http://file4.renrendoc.com/view2/M00/2F/03/wKhkFmY3W5OAJ1mqAAEQM1j_i6U3623.jpg)
![函数2省公开课一等奖全国示范课微课金奖_第4页](http://file4.renrendoc.com/view2/M00/2F/03/wKhkFmY3W5OAJ1mqAAEQM1j_i6U3624.jpg)
![函数2省公开课一等奖全国示范课微课金奖_第5页](http://file4.renrendoc.com/view2/M00/2F/03/wKhkFmY3W5OAJ1mqAAEQM1j_i6U3625.jpg)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
6第6章函数第1页第6章函数一、内容提要6.2~6.4函数定义,调用方法,函数返回值;6.5函数调用时参数传递
。6.7局部变量和全局变量
6.9内部函数和外部函数;6.10~6.12内置函数;函数重载;函数模板
6.13~6.14带默认形参值函数;预处理命令二、重点与难点1、函数定义、调用及函数参数传递2、全局变量、局部变量定义及应用
第2页函数(Function)是按给定任务,把相关语句组织在一起程序块,也称为例程或过程。函数分为标准库函数和用户自定义函数。
标准库函数:能够在任何程序中使用公共函数,由C++编译器提供。
用户自定义函数:必须按C++要求经过函数定义、函数说明、才能被调用,由用户自定义。程序从main()开始,一个函数能够调用其它函数,也能够被其它函数调用。函数与函数之间经过传递参数和返回值相联络。C++不允许函数嵌套定义。在一个函数中再定义一个函数是非法。§6.1函数概述voidmain(){voidfunc(){….}}第3页在一个程序文件中能够包含若干个函数。不论把一个程序划分为多少个程序模块,只能有一个main函数。程序总是从main函数开始执行。在程序运行过程中,由主函数调用其它函数,其它函数也能够相互调用。在C语言中没有类和对象,在程序模块中直接定义函数。能够认为,一个C程序是由若干个函数组成。C++面向过程程序设计沿用了C语言使用函数方法。在C++面向对象程序设计中,主函数以外函数大多是被封装在类中。主函数或其它函数能够经过类对象调用类中函数。不论是C还是C++,程序中各项操作基本上都是由函数来实现,程序编写者要依据需要编写一个个函数,每个函数用来实现某一功效。第4页在实际应用程序中,主函数写得很简单,它作用就是调用各个函数,程序各部分功效全部都是由各函数实现。主函数相当于总调度,调动各函数依次实现各项功效。开发商和软件开发人员将一些惯用功效模块编写成函数,放在函数库中供公共选取。程序开发人员要善于利用库函数,以降低重复编写程序段工作量。第5页下列图是一个程序中函数调用示意图。第6页在主函数中调用其它函数。#include<iostream>usingnamespacestd;voidprintstar(void)//定义printstar函数{cout<<″******************************″<<endl;//输出30个“*”}voidprint_message(void)//定义print_message函数{cout<<″WelcometoC++!″<<endl;//输出一行文字}intmain(){printstar();//调用printstar函数print_message();//调用print_message函数printstar();//调用printstar函数return0;}第7页运行情况以下:******************************WelcometoC++!******************************例7.3include<iostream>usingnamespacestd;floatadd(floatx,floaty){floatz;z=x+y;return(z);}intmain(){floata,b,c;cout<<"pleaseentera,b:";cin>>a>>b;c=add(a,b);cout<<"sum="<<c<<endl;return0;}第8页从用户使用角度看,函数有两种:(1)系统函数,即库函数。这是由编译系统提供,用户无须自己定义这些函数,能够直接使用它们。(2)用户自己定义函数。用以处理用户专门需要。从函数形式看,函数分两类:(1)无参函数。调用函数时无须给出参数。(2)有参函数。在调用函数时,要给出参数。在主调函数和被调用函数之间有数据传递。第9页§6.2函数定义1、定义无参函数普通形式为类型标识符函数名([void]){申明部分语句}前面例中printstar和print_message函数都是无参函数。用类型标识符指定函数类型,即函数带回来值类型。第10页2、定义有参函数普通形式为类型标识符函数名(形式参数表列){申明部分语句}比如:intmax(intx,inty)//函数首部,函数值为整型,有两个整型形参{intz;//函数体中申明部分z=x>y?x:y;//将x和y中大者值赋给整型变量zreturn(z);//将z值作为函数值返回调用点}C++要求在定义函数时必须指定函数类型。例6.4~6.6第11页在调用函数时,大多数情况下,函数是带参数。主调函数和被调用函数之间有数据传递关系。前面已提到:在定义函数时函数名后面括号中变量名称为形式参数(formalparameter,简称形参),在主调函数中调用一个函数时,函数名后面括号中参数(能够是一个表示式)称为实际参数(actualparameter,简称实参)。实际参数和形式参数第12页函数名([实参表列])假如是调用无参函数,则“实参表列”能够没有,但括号不能省略。假如实参表列包含多个实参,则各参数间用逗号隔开。实参加形参个数应相等,类型应匹配(相同或赋值兼容)。实参加形参按次序对应,一对一地传递数据。但应说明,假如实参表列包含多个实参,对实参求值次序并不是确定。例6.7
6.3.1函数调用普通形式§6.3函数调用第13页按函数在语句中作用来分,能够有以下3种函数调用方式:1.函数语句把函数调用单独作为一个语句,并不要求函数带回一个值,只是要求函数完成一定操作。如例中printstar();2.函数表示式函数出现在一个表示式中,这时要求函数带回一个确定值以参加表示式运算。如c=2*max(a,b);3.函数参数函数调用作为一个函数实参。如m=max(a,max(b,c));//max(b,c)是函数调用,其值作为外层max函数调用一个实参6.3.2函数调用方式第14页在一个函数中调用另一个函数(即被调用函数)需要具备哪些条件呢?(1)首先被调用函数必须是已经存在函数。(2)假如使用库函数,普通还应该在本文件开头用#include命令将相关头文件“包含”到本文件中来。(3)假如使用用户自己定义函数,而该函数与调用它函数(即主调函数)在同一个程序单位中,且位置在主调函数之后,则必须在调用此函数之前对被调用函数作申明。所谓函数申明(declare),就是在函数尚在未定义情况下,事先将该函数相关信息通知编译系统,方便使编译能正常进行。6.3.3对被调用函数申明和函数原型第15页例对被调用函数作申明。#include<iostream>usingnamespacestd;intmain(){floatadd(floatx,floaty);//对add函数作申明floata,b,c;cout<<″pleaseentera,b:″;cin>>a>>b;c=add(a,b);cout<<″sum=″<<c<<endl;return0;}floatadd(floatx,floaty)//定义add函数{floatz;z=x+y;return(z);}第16页运行情况以下:pleaseentera,b:123.68456.45↙sum=580.13注意:对函数定义和申明不是同一件事情。定义是指对函数功效确实立,包含指定函数名、函数类型、形参及其类型、函数体等,它是一个完整、独立函数单位。而申明作用则是把函数名字、函数类型以及形参个数、类型和次序(注意,不包含函数体)通知编译系统,方便在对包含函数调用语句进行编译时,据此对其进行对照检验(比如函数名是否正确,实参加形参类型和个数是否一致)。其实,在函数申明中也能够不写形参名,而只写形参类型,如第17页floatadd(float,float);这种函数申明称为函数原型(functionprototype)。使用函数原型是C和C++一个主要特点。它作用主要是:依据函数原型在程序编译阶段对调用函数正当性进行全方面检验。假如发觉与函数原型不匹配函数调用就汇报编译犯错。它属于语法错误。用户依据屏幕显示犯错信息很轻易发觉和纠正错误。函数原型普通形式为(1)函数类型函数名(参数类型1,参数类型2…);(2)函数类型函数名(参数类型1参数名1,参数类型2参数名2…);第18页第(1)种形式是基本形式。为了便于阅读程序,也允许在函数原型中加上参数名,就成了第(2)种形式。但编译系统并不检验参数名。所以参数名是什么都无所谓。上面程序中申明也能够写成floatadd(floata,floatb);//参数名不用x、y,而用a、b效果完全相同。应该确保函数原型与函数首部写法上一致,即函数类型、函数名、参数个数、参数类型和参数次序必须相同。在函数调用时函数名、实参类型和实参个数应与函数原型一致。第19页说明:(1)前面已说明,假如被调用函数定义出现在主调函数之前,能够无须加以申明。因为编译系统已经事先知道了已定义函数类型,会依据函数首部提供信息对函数调用作正确性检验。另外,用函数原型来申明函数,还能降低编写程序时可能出现错误。因为函数申明位置与函数调用语句位置比较近,所以在写程序时便于就近参考函数原型来书写函数调用,不易犯错。所以应养成对全部用到函数作申明习惯。这是确保程序正确性和可读性主要步骤。第20页(2)函数申明位置能够在调用函数所在函数中,也能够在函数之外。假如函数申明放在函数外部,在全部函数定义之前,则在各个主调函数中无须对所调用函数再作申明。比如:charletter(char,char);//本行和以下两行函数申明在全部函数之前且在函数外部floatf(float,float);//因而作用域是整个文件inti(float,float);intmain(){…}//在main函数中无须对它所调用函数作申明charletter(charc1,charc2)//定义letter函数{…}floatf(floatx,floaty)//定义f函数{…}inti(floatj,floatk)//定义i函数{…}假如一个函数被多个函数所调用,用这种方法比很好,无须在每个主调函数中重复申明。第21页(3)假如函数值类型和return语句中表示式值不一致时,则以函数类型为准。对数值型数据能够自动进行类型转换。比如:intmain(){intcount(intn);ints1;…..s1=count(10);…..return(0)}intcount(intn)//返回值是整型{floats;……return(s);}第22页函数返回值是经过函数中return语句取得。return语句将被调用函数中一个确定值带回主调函数中去。return语句后面括号能够要,也能够不要。return后面值能够是一个表示式。例6.8p90说明(2)函数值类型。既然函数有返回值,这个值当然应属于某一个确定类型,应该在定义函数时指定函数值类型。P91§6.4函数返回值第23页§6.5调用函数时数据传递1、值传递#include<iostream>usingnamespacestd;intmax(intx,inty)//定义有参函数max{intz;z=x>y?x:y;return(z);}intmain(){inta,b,c;cout<<″pleaseentertwointegernumbers:″;cin>>a>>b;c=max(a,b);//调用max函数,给定实参为a,b。函数值赋给ccout<<″max=″<<c<<endl;return0;}第24页运行情况以下:pleaseentertwointegernumbers:23↙max=3图4.2第25页相关形参加实参说明:(1)在定义函数时指定形参,在未出现函数调用时,它们并不占内存中存放单元,所以称它们是形式参数或虚拟参数,表示它们并不是实际存在数据,只有在发生函数调用时,函数max中形参才被分配内存单元,方便接收从实参传来数据。在调用结束后,形参所占内存单元也被释放。(2)实参能够是常量、变量或表示式,如max(3,a+b);但要求a和b有确定值。方便在调用函数时将实参值赋给形参。(3)在定义函数时,必须在函数首部指定形参类型。第26页(4)实参加形参类型应相同或赋值兼容。例中实参和形参都是整型,这是正当、正确。假如实参为整型而形参为实型,或者相反,则按不一样类型数值赋值规则进行转换。比如实参a值为3.5,而形参x为整型,则将3.5转换成整数3,然后送到形参b。字符型与整型能够相互通用。(5)实参变量对形参变量数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实参。在调用函数时,编译系统暂时给形参分配存放单元。请注意:实参单元与形参单元是不一样单元。下列图表示将例6.11实参a和b值2和3传递给对应形参x和y。第27页图a图b调用结束后,形参单元被释放,实参单元仍保留并维持原值。所以,在执行一个被调用函数时,形参值假如发生改变,并不会改变主调函数中实参值。比如,若在执行max函数过程中形参x和y值变为10和15,调用结束后,实参a和b仍为2和3,见上图。第28页2、地址传递采取值传递方式不能经过形参值改变实参,要实现值双向传递通常使用地址传递。常量和变量能够用作函数实参,一样数组元素也能够作函数实参,其使用方法与变量相同。数组名也能够作实参和形参,传递是数组起始地址。,此时实参加形参都用数组名(也能够用指针变量,见第8章)例7.11用选择法对数组中10个整数按由小到大排序。#include<iostream>usingnamespacestd;intmain()第29页{voidselect_sort(intarray[],intn);//函数申明inta[10],i;cout<<″entertheoriginlarray:″<<endl;for(i=0;i<10;i++)//输入10个数cin>>a[i];cout<<endl;select_sort(a,10);cout<<″thesortedarray:″<<endl;for(i=0;i<10;i++)cout<<a[i]<<″″;cout<<endl;return0;}voidselect_sort(intarray[],intn){inti,j,k,t;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++)if(array[j]<array[k])k=j;t=array[k];array[k]=array[i];array[i]=t;}}第30页运行情况以下:entertheoriginlarray:69-2568711-543077↙//输入10个数thesortedarray:-54-2036911567787关于用数组名作函数参数有两点要说明:(1)假如函数实参是数组名,形参也应为数组名(或指针变量,关于指针见第8章),形参不能申明为普通变量(如intarray;)。实参数组与形参数组类型应一致(现都为int型),如不一致,结果将犯错。(2)需要尤其说明是:数组名代表数组首元素地址,并不代表数组中全部元素。所以用数组名作函数实参时,不是把实参数组值传递给形参,而只是将实参数组首元素地址传递给形参。第31页形参能够是数组,也能够是指针变量,它们用来接收实参传来地址。在调用函数时,将实参数组首元素地址传递给形参数组名。这么,实参数组和形参数组就共占同一段内存单元。见下列图。第32页
在用变量作函数参数时,只能将实参变量值传给形参变量,在调用函数过程中假如改变了形参值,对实参没有影响,即实参值不因形参值改变而改变。而用数组名作函数实参时,改变形参数组元素值将同时改变实参数组元素值。在程序设计中往往有意识地利用这一特点改变实参数组元素值。实际上,申明形参数组并不意味着真正建立一个包含若干元素数组,在调用函数时也不对它分配存放单元,只是用array[]这么形式表示array是一维数组名,以接收实参传来地址。所以array[]中方括号内数值并无实际作用,编译系统对一维数组方括号内内容不予处理。形参一维数组申明中能够写元素个数,也能够不写。第33页函数首部下面几个写法都正当,作用相同。voidselect_sort(intarray[10],intn)//指定元素个数与实参数组相同voidselect_sort(intarray[],intn)//不指定元素个数voidselect_sort(intarray[5],intn)//指定元素个数与实参数组不一样在学习第8章时能够深入知道,C++实际上只把形参数组名作为一个指针变量来处理,用来接收从实参传过来地址。前面提到一些现象都是由此而产生。第34页引用方式以引用作为参数,既能够使形参任何操作能改变对应实参数据格式以下voidswap(int&x,int&y)引用方式形参并不分配空间,而是在调用该函数后将形参变量约束到对应实参上,型参就是实参别名,实参必须是变量或者数组元素,不能是表示式例7.13第35页对一个数据能够使用“引用”(reference),这是C++对C一个主要扩充,引用是一个新变量类型,它作用是为一个变量起一个别名。假如有一个变量a,想给它起一个别名b,能够这么写:inta;//定义a是整型变量int&b=a;//申明b是a引用以上语句申明了b是a引用,即b是a别名。经过这么申明后,a或b作用相同,都代表同一变量。引用
什么是变量引用第36页注意:在上述申明中,&是引用申明符,并不代表地址。不要了解为“把a值赋给b地址”。申明变量b为引用类型,并不需要另外开辟内存单元来存放b值。b和a占内存中同一个存放单元,它们含有同一地址。申明b是a引用,能够了解为:使变量b含有变量a地址。见图,假如a值是20,则b值也是20。第37页在申明一个引用类型变量时,必须同时使之初始化,即申明它代表哪一个变量。在申明变量b是变量a引用后,在它们所在函数执行期间,该引用类型变量b一直与其代表变量a相联络,不能再作为其它变量引用(别名)。下面使用方法不对:inta1,a2;int&b=a1;int&b=a2;//企图使b又变成a2引用(别名)是不行第38页有了变量名,为何还需要一个别名呢?C++之所以增加引用类型,主要是把它作为函数参数,以扩充函数传递数据功效。引用作为函数参数第39页#include<iostream>usingnamespacestd;intmain(){voidswap(int,int);//函数申明inti=3,j=5;swap(i,j);//调用函数swapcout<<i<<″″<<j<<endl;//i和j值未交换return0;}voidswap(inta,intb)//企图经过形参a和b值交换,实现实参i和j值交换{inttemp;temp=a;//以下3行用来实现a和b值交换a=b;b=temp;}第40页第41页利用“引用形参”实现两个变量值交换。intmain(){voidswap(int&,int&);inti=3,j=5;swap(i,j);cout<<″i=″<<i<<″″<<″j=″<<j<<endl;return0;}voidswap(int&a,int&b)//形参是引用类型{inttemp;temp=a;a=b;b=temp;}第42页输出结果为i=5j=3在swap函数形参表列中申明a和b是整型变量引用。第43页实际上,在虚实结合时是把实参i地址传到形参a,使形参a地址取实参i地址,从而使a和i共享同一单元。一样,将实参j地址传到形参b,使形参b地址取实参j地址,从而使b和j共享同一单元。这就是地址传递方式。为便于了解,能够通俗地说:把变量i名字传给引用变量a,使a成为i别名。第44页在一个函数内部定义变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量。一样,在复合语句中定义变量只在本复合语句范围内有效。这称为局部变量(localvariable)。如6.7局部变量和全局变量
6.7.1局部变量第45页floatf1(inta) //函数f1{intb,c; b、c有效 a有效┆}charf2(intx,inty) //函数f2{inti,j; x,y有效i、j有效 }intmain() //主函数{intm,n;┆{intp,q; p、q在复合语句中有效 m、n有效┆}}第46页说明:(1)主函数main中定义变量(m,n)也只在主函数中有效,不会因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其它函数中定义变量。(2)不一样函数中能够使用同名变量,它们代表不一样对象,互不干扰。比如,在f1函数中定义了变量b和c,倘若在f2函数中也定义变量b和c,它们在内存中占不一样单元,不会混同。(3)能够在一个函数内复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为分程序或程序块。(4)形式参数也是局部变量。比如f1函数中形参a也只在f1函数中有效。其它函数不能调用。第47页(5)在函数申明中出现参数名,其作用范围只在本行括号内。实际上,编译系统对函数申明中变量名是忽略,即使在调用函数时也没有为它们分配存放单元。比如intmax(inta,intb);//函数申明中出现a、b┆intmax(intx,inty)//函数定义,形参是x、y{cout<<x<<y<<endl;//正当,x、y在函数体中有效cout<<a<<b<<endl;//非法,a、b在函数体中无效}第48页前面已介绍,程序编译单位是源程序文件,一个源文件能够包含一个或若干个函数。在函数内定义变量是局部变量,而在函数之外定义变量是外部变量,称为全局变量(globalvariable,也称全程变量)。全局变量有效范围为从定义变量位置开始到根源文件结束。如6.7.2全局变量第49页intp=1,q=5;//全局变量 floatf1(a)//定义函数f1inta;{intb,c;┆}charc1,c2;//全局变量 全局变量p、q作用范围charf2(intx,inty)//定义函数f2{inti,j;┆全局变量c1、c2作用范围
}main()//主函数{intm,n;┆}第50页p、q、c1、c2都是全局变量,但它们作用范围不一样,在main函数和f2函数中能够使用全局变量p、q、c1、c2,但在函数f1中只能使用全局变量p、q,而不能使用c1和c2。在一个函数中既能够使用本函数中局部变量,又能够使用有效全局变量。说明:(1)设全局变量作用是增加函数间数据联络渠道。(2)提议不在必要时不要使用全局变量,因为:①全局变量在程序全部执行过程中都占用存放单元,而不是仅在需要时才开辟单元。第51页②它使函数通用性降低了,因为在执行函数时要受到外部变量影响。假如将一个函数移到另一个文件中,还要将相关外部变量及其值一起移过去。但若该外部变量与其它文件变量同名,就会出现问题,降低了程序可靠性和通用性。在程序设计中,在划分模块时要求模块内聚性强、与其它模块耦合性弱。即模块功效要单一(不要把许多互不相干功效放到一个模块中),与其它模块相互影响要尽可能少,而用全局变量是不符合这个标准。普通要求把程序中函数做成一个封闭体,除了能够经过“实参——形参”渠道与外界发生联络外,没有其它渠道。这么程序移植性好,可读性强。第52页③使用全局变量过多,会降低程序清楚性。在各个函数执行时都可能改变全局变量值,程序轻易犯错。所以,要限制使用全局变量。(3)假如在同一个源文件中,全局变量与局部变量同名,则在局部变量作用范围内,全局变量被屏蔽,即它不起作用。变量有效范围称为变量作用域(scope)。归纳起来,变量有4种不一样作用域:文件作用域(filescope)、函数作用域(functionscope)、块作用域(blockscope)和函数原型作用域(functionprototypescope)。文件作用域是全局,其它三者是局部。第53页作用域是从空间角度来分析,分为全局变量和局部变量。变量还有另一个属性——存放期(storageduration,也称生命期)。存放期是指变量在内存中存在期间。这是从变量值存在时间角度来分析。存放期能够分为静态存放期(staticstorageduration)和动态存放期(dynamicstorageduration)。这是由变量静态存放方式和动态存放方式决定。6.8变量存放类别和其作用域
动态存放方式与静态存放方式第54页所谓静态存放方式是指在程序运行期间,系统对变量分配固定存放空间。而动态存放方式则是在程序运行期间,系统对变量动态地分配存放空间。先看一下内存中供用户使用存放空间情况。这个存放空间能够分为三部分,即:(1)程序区(2)静态存放区(3)动态存放区
第55页数据分别存放在静态存放区和动态存放区中。全局变量全部存放在静态存放区中,在程序开始执行时给全局变量分配存放单元,程序执行完成就释放这些空间。在程序执行过程中它们占据固定存放单元,而不是动态地进行分配和释放。在动态存放区中存放以下数据:①函数形式参数。在调用函数时给形参分配存放空间。②函数中自动变量(未加static申明局部变量,详见后面介绍)。③函数调用时现场保护和返回地址等。对以上这些数据,在函数调用开始时分配动态存放空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态,假如在一个程序中两次调用同一函数,则要进行两次分配和释放,而两次分配给此函数中局部变量存放空间地址可能是不相同。第56页假如在一个程序中包含若干个函数,每个函数中局部变量存放期并不等于整个程序执行周期,它只是整个程序执行周期一部分。依据函数调用情况,系统对局部变量动态地分配和释放存放空间。在C++中变量除了有数据类型属性之外,还有存放类别(storageclass)属性。存放类别指是数据在内存中存放方法。存放方法分为静态存放和动态存放两大类。详细包含4种:自动(auto)、静态(static)、存放器(register)和外部(extern)。依据变量存放类别,能够知道变量作用域和存放期。第57页函数中局部变量,假如不用关键字static加以申明,编译系统对它们是动态地分配存放空间。函数形参和在函数中定义变量(包含在复合语句中定义变量)都属这类。在调用该函数时,系统给形参和函数中定义变量分配存放空间,数据存放在动态存放区中。在函数调用结束时就自动释放这些空间。假如是在复合语句中定义变量,则在变量定义时分配存放空间,在复合语句结束时自动释放空间。所以这类局部变量称为自动变量(autovariable)。自动变量用关键字auto作存放类别申明。比如:6.8.1局部变量及其存放类型第58页intf(inta)//定义f函数,a为形参{autointb,c=3;//定义b和c为整型自动变量┆}存放类别auto和数据类型int次序任意。关键字auto能够省略,假如不写auto,则系统把它默认为自动存放类别,它属于动态存放方式。程序中大多数变量属于自动变量。本书前面各章所介绍例子中,在函数中定义变量都没有申明为auto,其实都默认指定为自动变量。在函数体中以下两种写法作用相同:①autointb,c=3;②intb,c=3;第59页有时希望函数中局部变量值在函数调用结束后不消失而保留原值,即其占用存放单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时值。这时就应该指定该局部变量为静态局部变量(staticlocalvariable)。静态局部变量第60页#include<iostream>usingnamespacestd;intf(inta)//定义f函数,a为形参{autointb=0;//定义b为自动变量staticintc=3;//定义c为静态局部变量b=b+1;c=c+1;returna+b+c;}
intmain(){inta=2,i;for(i=0;i<3;i++)cout<<f(a)<<″″;cout<<endl;return0;}第61页运行结果为789先后3次调用f函数时,b和c值如书中表4.1所表示。图4.14第62页对静态局部变量说明:(1)静态局部变量在静态存放区内分配存放单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存放类别,存放在动态存放区空间(而不是静态存放区空间),函数调用结束后即释放。(2)为静态局部变量赋初值是在编译时进行值,即只赋初值一次,在程序运行时它已经有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时值。而为自动变量赋初值,不是在编译时进行,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。第63页(3)假如在定义局部变量时不赋初值话,对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,假如不赋初值,则它值是一个不确定值。这是因为每次函数调用结束后存放单元已释放,下次调用时又重新另分配存放单元,而所分配单元中值是不确定。(4)即使静态局部变量在函数调用结束后依然存在,但其它函数是不能引用它,也就是说,在其它函数中它是“不可见”。在什么情况下需要用局部静态变量呢?(1)需要保留函数上一次调用结束时值。比如能够用下例中方法求n!。第64页输出1~5阶乘值(即1!,2!,3!,4!,5!)。#include<iostream>usingnamespacestd;intfac(int);//函数申明intmain(){inti;for(i=1;i<=5;i++)cout<<i<<″!=″<<fac(i)<<endl;return0;}intfac(intn){staticintf=1;//f为静态局部变量,函数结束时f值不释放f=f*n;//在f原值基础上乘以nreturnf;}第65页运行结果为1!=12!=23!=64!=245!=120每次调用fac(i),就输出一个i,同时保留这个i!值,方便下次再乘(i+1)。(2)假如初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。不过应该看到,用静态存放要多占内存,而且降低了程序可读性,当调用次数多时往往弄不清静态局部变量当前值是什么。所以,如无须要,不要多用静态局部变量。第66页普通情况下,变量值是存放在内存中。当程序中用到哪一个变量值时,由控制器发出指令将内存中该变量值送到CPU中运算器。经过运算器进行运算,假如需要存数,再从运算器将数据送到内存存放。如图所表示。
3.用register申明存放器变量第67页为提升执行效率,C++允许将局部变量值放在CPU中存放器中,需要用时直接从存放器取出参加运算,无须再到内存中去存取。这种变量叫做存放器变量,用关键字register作申明。比如,能够将上例中fac函数改写以下:intfac(intn){registerinti,f=1;//定义i和f是存放器变量for(i=1;i<=n;i++)f=f*i;returnf;}定义f和i是存放在存放器局部变量,假如n值大,则能节约许多执行时间。在程序中定义存放器变量对编译系统只是提议性(而不是强制性)。当今优化编译系统能够识别使用频繁变量,自动地将这些变量放在存放器中。第68页全局变量(外部变量)是在函数外部定义,它作用域为从变量定义处开始,到本程序文件末尾。在此作用域内,全局变量能够为本文件中各个函数所引用。编译时将全局变量分配在静态存放区。全局变量存放类型能够有两种:外部和静态6.8.2全局变量及其存放类型第69页1.在一个文件内申明全局变量假如外部变量不在文件开头定义,其有效作用范围只限于定义处到文件终了。假如在定义点之前函数想引用该全局变量,则应该在引用之前用关键字extern对该变量作外部变量申明,表示该变量是一个将在下面定义全局变量。有了此申明,就能够从申明处起,正当地引用该全局变量,这种申明称为提前引用申明。第70页用extern对外部变量作提前引用申明,以扩展程序文件中作用域。例7.18#include<iostream>usingnamespacestd;intmax(int,int);//函数申明voidmain(){externinta,b;//对全局变量a,b作提前引用申明cout<<max(a,b)<<endl;}inta=15,b=-7;//定义全局变量a,bintmax(intx,inty){intz;z=x>y?x:y;returnz;}第71页运行结果以下:15在main后面定义了全局变量a,b,但因为全局变量定义位置在函数main之后,所以假如没有程序第5行,在main函数中是不能引用全局变量a和b。现在我们在main函数第2行用extern对a和b作了提前引用申明,表示a和b是将在后面定义变量。这么在main函数中就能够正当地使用全局变量a和b了。假如不作extern申明,编译时会犯错,系统认为a和b未经定义。普通都把全局变量定义放在引用它全部函数之前,这么能够防止在函数中多加一个extern申明。第72页2.在多文件程序中申明外部变量假如一个程序包含两个文件,在两个文件中都要用到同一个外部变量num,不能分别在两个文件中各自定义一个外部变量num。正确做法是:在任一个文件中定义外部变量num,而在另一文件中用extern对num作外部变量申明。即externintnum;编译系统由此知道num是一个已在别处定义外部变量,它先在本文件中找有没有外部变量num,假如有,则将其作用域扩展到本行开始(如上节所述),假如本文件中无另外部变量,则在程序连接时从其它文件中找有没有外部变量num,假如有,则把在另一文件中定义外部变量num作用域扩展到本文件,在本文件中能够正当地引用该外部变量num。第73页分析下例:file1.cppfile2.cppexterninta,b;inta=3,b=4;intmain()┆{cout<<a<<″,″<<b<<endl;return0;}用extern扩展全局变量作用域,即使能为程序设计带来方便,但应十分慎重,因为在执行一个文件中函数时,可能会改变了该全局变量值,从而会影响到另一文件中函数执行结果。第74页有时在程序设计中希望一些外部变量只限于被本文件引用,而不能被其它文件引用。这时能够在定义外部变量时加一个static申明。比如:file1.cppfile2.cppstaticinta=3;externinta;intmain()intfun(intn){{┆┆a=a*n;┆}}用static申明静态外部变量第75页这种加上static申明、只能用于本文件外部变量(全局变量)称为静态外部变量。这就为程序模块化、通用性提供了方便。假如已知道其它文件不需要引用本文件全局变量,能够对本文件中全局变量都加上static,成为静态外部变量,以免被其它文件误用。需要指出,不要误认为用static申明外部变量才采取静态存放方式(存放在静态存放区中),而不加static是动态存放(存放在动态存放区)。实际上,两种形式外部变量都用静态存放方式,只是作用范围不一样而已,都是在编译时分配内存。第76页6.9内部函数和外部函数一个C++程序由若干个函数组成,这些函数能够都在一个程序文件中,也能够分散在多个程序文件中。依据函数能否被其它源文件调用,可将函数分为内部函数和外部函数。6.9.1内部函数只能被本文件中其它函数调用函数称为内部函数(静态函数),定义内部函数需要在函数定义前面冠以static说明。比如:staticfloathust(inta,intb){…}第77页6.9.2外部函数在函数定义最左端冠以extern说明符函数,称为外部函数,表示此函数可被其它文件调用普通格式:extern类型标识符函数名(形参表)说明:(1)省略extern说明符默认为外部函数(2)在需要调用外部函数文件中用关键字extern对函数作申明。例6.17第78页6.10内置函数调用函数时需要一定时间和空间开销。下列图表示函数调用过程:第79页C++提供一个提升效率方法,即在编译时将所调用函数代码直接嵌入到主调函数中,而不是将流程转出去。这种嵌入到主调函数中函数称为内置函数(inlinefunction),又称内嵌函数。在有些书中把它译成内联函数。指定内置函数方法很简单,只需在函数首行左端加一个关键字inline即可。第80页函数指定为内置函数。#include<iostream>usingnamespacestd;inlineintmax(int,int,int);//申明函数,注意左端有inlineintmain(){inti=10,j=20,k=30,m;m=max(i,j,k);cout<<″max=″<<m<<endl;return0;}inlineintmax(inta,intb,intc)//定义max为内置函数{if(b>a)a=b;//求a,b,c中最大者if(c>a)a=c;returna;}第81页因为在定义函数时指定它为内置函数,所以编译系统在碰到函数调用“max(i,j,k)”时,就用max函数体代码代替“max(i,j,k)”,同时将实参代替形参。这么,程序第6行“m=max(i,j,k);”就被置换成if(j>i)i=j;if(k>i)i=k;m=i;注意:能够在申明函数和定义函数时同时写inline,也能够只在其中一处申明inline,效果相同,都能按内置函数处理。使用内置函数能够节约运行时间,但却增加了目标程序长度。所以普通只将规模很小(普通为5个语句以下)而使用频繁函数(如定时采集数据函数)申明为内置函数。第82页内置函数中不能包含复杂控制语句,如循环语句和switch语句。应该说明:对函数作inline申明,只是程序设计者对编译系统提出一个提议,也就是说它是提议性,而不是指令性。并非一经指定为inline,编译系统就必须这么做。编译系统会依据详细情况决定是否这么做。归纳起来,只有那些规模较小而又被频繁调用简单函数,才适合于申明为inline函数。第83页在编程时,有时我们要实现是同一类功效,只是有些细节不一样。比如希望从3个数中找出其中最大者,而每次求最大数时数据类型不一样,可能是3个整数、3个双精度数或3个长整数。程序设计者往往会分别设计出3个不一样名函数,其函数原型为:intmax1(inta,intb,intc);//求3个整数中最大者doublemax2(doublea,doubleb,doublec);//求3个双精度数中最大者longmax3(longa,longb,longc);//求3个长整数中最大者C++允许用同一函数名定义多个函数,这些函数参数个数和参数类型不一样。这就是函数重载(functionoverloading)。即对一个函数名重新赋予它新含义,使一个函数名能够多用。6.11函数重载第84页例求3个数中最大数(分别考虑整数、双精度数、长整数情况)。#include<iostream>usingnamespacestd;intmain(){intmax(inta,intb,intc);//函数申明doublemax(doublea,doubleb,doublec);//函数申明inti1,i2,i3,i;cin>>i1>>i2>>i3;//输入3个整数i=max(i1,i2,i3);//求3个整数中最大者cout<<″i_max=″<<i<<endl;doubled1,d2,d3,d;cin>>d1>>d2>>d3;//输入3个双精度数d=max(d1,d2,d3);//求3个双精度数中最大者cout<<″d_max=″<<d<<endl;}第85页intmax(inta,intb,intc)//定义求3个整数中最大者函数{if(b>a)a=b;if(c>a)a=c;returna;}doublemax(doublea,doubleb,doublec)//定义求3个双精度数中最大者函数{if(b>a)a=b;if(c>a)a=c;returna;}上例2个max函数函数体是相同,其实重载函数并不要求函数体相同。重载函数除了允许参数类型不一样以外,还允许参数个数不一样。第86页C++提供了函数模板(functiontemplate)。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不详细指定,用一个虚拟类型来代表。这个通用函数就称为函数模板。凡是函数体相同函数都能够用这个模板来代替,无须定义多个函数,只需在模板中定义一次即可。在调用函数时系统会依据实参类型来取代模板中虚拟类型,从而实现了不一样函数功效。看下面例子就清楚了。例6.20将前例程序改为经过函数模板来实现。6.12函数模板第87页#include<iostream>usingnamespacestd;template<typenameT>//模板申明,其中T为类型参数Tmax(Ta,Tb,Tc)//定义一个通用函数,用T作虚拟类型名{if(b>a)a=b;if(c>a)a=c;returna;}intmain(){inti1=185,i2=-76,i3=567,i;doubled1=56.87,d2=90.23,d3=-3214.78,d;longg1=67854,g2=-912456,g3=673456,g;i=max(i1,i2,i3);//调用模板函数,此时T被int取代d=max(d1,d2,d3);//调用模板函数,此时T被double取代g=max(g1,g2,g3);//调用模板函数,此时T被long取代cout<<″i_max=″<<i<<endl;cout<<″f_max=″<<f<<endl;cout<<″g_max=″<<g<<endl;return0;}第88页程序第3~8行是定义模板。定义函数模板普通形式为template<typenameT>或template<classT>通用函数定义通用函数定义在建立函数模板时,只要将例6.20程序中定义第一个函数首部int改为T即可。即用虚拟类型名T代替详细数据类型。在对程序进行编译时,碰到第13行调用函数max(i1,i2,i3),编译系统会将函数名max与模板max相匹配,将实参类型取代了函数模板中虚拟类型T。此时相当于已定义了一个函数:第89页intmax(inta,intb,intc){if(b>a)a=b;if(c>a)a=c;returna;}然后调用它。后面两行(14,15行)情况类似。类型参数能够不只一个,能够依据需要确定个数。如template<classT1,typenameT2>能够看到,用函数模板比函数重载更方便,程序更简练。但应注意它只适合用于函数参数个数相同而类型不一样,且函数体相同情况,假如参数个数不一样,则不能用函数模板。第90页普通情况下,在函数调用时形参从实参那里取得值,所以实参个数应与形参相同。有时屡次调用同一函数时用一样实参,C++提供简单处理方法,给形参一个默认值,这么形参就无须一定要从实参取值了。如有一函数申明floatarea(floatr=6.5);指定r默认值为6.5,假如在调用此函数时,确认r值为6.5,则能够无须给出实参值,如area();//相当于area(6.5);假如不想使形参取此默认值,则经过实参另行给出。如6.13有默认参数函数第91页area(7.5);//形参得到值为7.5,而不是6.5这种方法比较灵活,能够简化编程,提升运行效率。假如有多个形参,能够使每个形参有一个默认值,也能够只对一部分形参指定默认值,另一部分形参不指定默认值。如有一个求圆柱体体积函数,形参h代表圆柱体高,r为圆柱体半径。函数原型以下:floatvolume(floath,floatr=12.5);//只对形参r指定默认值12.5函数调用能够采取以下形式:volume(45.6);//相当于volume(45.6,12.5)volume(34.2,10.4)//h值为34.2,r值为10.4实参加形参结合是从左至右次序进行。所以指定默认值参数必须放在形参表列中最右端,不然犯错。比如:第92页voidf1(floata,intb=0,intc,chard=′a′);//不正确voidf2(floata,intc,intb=0,chard=′a′);//正确假如调用上面f2函数,能够采取下面形式:f2(3.5,5,3,′x′)//形参值全部从实参得到f2(3.5,5,3)//最终一个形参值取默认值′a′f2(3.5,5)//最终两个形参值取默认值在调用有默认参数函数时,实参个数能够与形参个数不一样,实参未给定,从形参默认值得到值。利用这一特征,能够使函数使用愈加灵活。比如、求2个数或3个数中最大数。也能够不用重载函数,而改用带有默认参数函数。第93页例求2个或3个正整数中最大数,用带有默认参数函数实现。#include<iostream>usingnamespacestd;intmain(){intmax(inta,intb,intc=0);//函数申明,形参c有默认值inta,b,c;cin>>a>>b>>c;cout<<″max(a,b,c)=″<<max(a,b,c)<<endl;//输出3个数中最大cout<<″max(a,b)=″<<max(a,b)<<endl;//输出2个数中最大return0;}intmax(inta,intb,intc)//函数定义{if(b>a)a=b;if(c>a)a=c;returna;}第94页能够在C++源程序中加入一些“预处理命令”(preprocessordirectives),以改进程序设计环境,提升编程效率。预处理命令是C++统一要求,不过它不是C++语言本身组成部分,不能直接对它们进行编译(因为编译程序不能识别它们)。现在使用C++编译系统都包含了预处理、编译和连接等部分,所以不少用户误认为预处理命令是C++语言一部分,甚至认为它们是C++语句,这是不正确。必须正确区分预处理命令和C++语句,区分预处理和编译,才能正确使用预处理命令。C++与其它高级语言一个主要区分是能够使用预处理命令和含有预处理功效。6.14预处理命令第95页C++提供预处理功效主要有以下3种:(1)宏定义(2)文件包含(3)条件编译分别用宏定义命令、文件包含命令、条件编译命令来实现。为了与普通C++语句相区分,这些命令以符号“#”开头,而且末尾不包含分号。第96页能够用#define命令将一个指定标识符(即宏名)来代表一个字符串。定义宏作用普通是用一个短名字代表一个长字符串。它普通形式为#define标识符字符串这就是已经介绍过定义符号常量。如#definePI3.1415926还能够用#define命令定义带参数宏定义。其定义普通形式为#define宏名(参数表)字符串如#defineS(a,b)a*b//定义宏S(矩形面积),a、b为宏参数宏定义第97页使用形式以下:area=S(3,2)用3、2分别代替宏定义中形式参数a和b,即用3*2代替S(3,2)。所以赋值语句展开为area=3*2;因为C++增加了内置函数(inline),比用带参数宏定义更方便,所以在C++中基本上已不再用#define命令定义宏了,主要用于条件编译中。第98页1.“文件包含”作用所谓“文件包含”处理是指一个源文件能够将另外一个源文件全部内容包含进来,即将另外文件包含到本文件之中。C++提供了#in
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- DB3702T 46.1-2024地理标志产品 平度大花生 第1部分:生产技术规程
- 二手货物交易合同样本
- 个人对个人贷款合同样本参考
- XX区青少年活动中心建设项目合同
- 专项建筑企业流动资金贷款合同
- 个人间借款合同格式及条款解析
- 中外贸易合作合同条款
- 产品试用合同范本
- VI设计合同模板及条款范例
- 二手车买卖正式合同书模板
- 允许一切发生:过不紧绷松弛的人生
- 注塑生产过程控制流程
- 教科版六年级科学下册 (厨房里的物质与变化)教学课件
- 一年级下册口算题(可直接打印)
- 公务员面试应急应变题目大全及解析
- 浙江省炮制规范2015版电子版
- 冰心《童年的春节》
- 郑州小吃详细地点
- 上海高考英语词汇手册
- 2021年江苏省淮安市淮阴中学高一政治下学期期末试题含解析
- 公共政策工具-课件
评论
0/150
提交评论