1第3章函数皮德常nuaacs@126.com23.1函数的定义和调用1.函数:库函数和用户自定义函数。2.使用函数的原因之一:将程序分解成更小,更易管理的程序单元。3.原则:一个C++程序由若干个函数构成,其中一个是主函数,是程序执行入口,其它函数是子函数。子函数间可以相互调用,但主函数只能调用其他子函数,而不能被其他子函数调用。33.1.2定义函数•一般形式:类型函数名(参数列表){函数体}例如:求两个整数中的昀大值。intmax(intx,inty){returnxy?x:y;}4注意如下几点:(1)无返回值、有形参的函数。例如:voiddisplay(intx){coutHellox;}(2)无返回值,也没有参数的函数。例如:voiddisplay(){coutHello;}(3)有返回值,但没有形参的函数。例如:intinput(){intx;cinx;returnx;}(4)有返回值,有形参的函数。如前面的max函数。53.1.3调用函数•格式:函数名(实际参数表);•调用无返回值的函数:完成某个功能操作,可单独作为函数调用语句使用;•调用有返回值的函数:将产生一个数值,函数调用通常出现在表达式中。•【例3.1】输入两个整数,求其中较大的一个数。intmax(intx,inty){returnxy?x:y;}intmain(){inta,b;cout请输入两个整数:;cinab;cout昀大值是:max(a,b)endl;return0;}思考:函数头与函数调用的区别。73.2函数的声明•C++对函数之间的排列没有顺序上的要求,但要满足“先定义后使用”。•对自定义函数:对先定义、后调用的函数可以不用声明;但后定义、先调用的函数必须声明。•函数原型:由函数定义抽取出来的能代表函数特征的部分,包括:函数类型、函数名、形参个数及其类型。它描述了一个函数的特征。【例3.2】验证哥德巴赫猜想。编程:将960到970之间的全部偶数都分解成两个素数之和。boolprime(intx);intmain(){intx,n;for(n=960;n=970;n=n+2)for(x=2;x=n/2;x++)if(prime(x)&&prime(n-x)){coutn=x+n-xendl;break;}return0;}boolprime(intx){inti,k;k=(int)sqrt(x);for(i=2;i=k;i++)if(x%i==0)returnfalse;returntrue;}93.3函数的参数传递和返回值3.3.1函数参数的传递方式•函数调用时,先将实参的值按照位置传递给对应的形参。一般情况下,实参与形参的个数及顺序应该是一一对应,并且类型要匹配。实参与形参的名字不要求相同。•C++支持两种参数传递:传值和传引用。【3.3】交换变量的值。voidswap(intx,inty);intmain(){inta=10,b=20;swap(a,b);coutsetw(6)asetw(6)bendl;return0;}voidswap(intx,inty){intt;t=x;x=y;y=t;coutsetw(6)xsetw(6)yendl;}注意:遇到函数调用时,采用实参值来初始化相应的形参。即实参与形参的结合,发生在对形参变量分配空间时。113.3.2函数的返回值函数返回到调用者有两种方法:(1)对于没有返回值的函数,当函数的昀后一条语句执行完毕后,函数终止并且返回到调用者,由调用者继续程序的执行。(2)对于有返回值的函数,必须采用return语句将要返回的值返回给调用者。格式为:return表达式;12【例3.4】求10~1000之内的所有数x,满足:x、x2和x3均是迴文数据。boolpalindrome(intn);intmain(){intx;coutxx*xx*x*xendl;for(x=10;x=1000;x++)if(palindrome(x)&&palindrome(x*x)&&palindrome(x*x*x))coutxsetw(8)x*xsetw(10)x*x*xendl;return0;}boolpalindrome(intn){intm=0,t=n;while(n!=0){m=m*10+n%10;n/=10;}returnm==t;}14常问的3个问题(1)一个函数可以有多个参数,但一个函数昀多只能返回一个值。(2)如果一个函数的返回值类型不是void,那么该函数必须包含return语句。(3)函数的返回值是如何返回到调用处的。153.4局部变量和全局变量•基本概念:1.可见:指变量可以正常使用;2.生存:指变量在内存中占有单元。有时,某变量在内存中占有单元,但却不能使用;3.仅在某些函数或某些代码段中可见的变量,称为局部变量;4.如果在整个程序中都可见的变量,称为全部变量。163.4.1内存存储区的布局173.4.2局部变量•范围:函数内或复合语句块;•存储在栈中;•执行到定义局部变量的语句时,在栈中分配空间。当执行完毕,按先进后出的顺序依次释放。•局部变量定义时前面可加auto,但常省略。•若未显示赋值或初始化,其初值不确定。voidswap(intx,inty);//分析局部变量intmain(){autointx=10,y=20;swap(x,y);coutsetw(6)xsetw(6)yendl;return0;}voidswap(intx,inty){intt;t=x;x=y;y=t;coutsetw(6)xsetw(6)yendl;}193.4.3全局变量•全局变量:在函数外定义的变量(1)全局变量存放在全局数据区,自动初始化为0。(2)作用域是从变量定义处开始到文件结束。(3)如果程序的某个函数修改了全局变量,其他函数都“可见”修改后结果。inta;voidfun(){couta;a=200;}intmain(){inta=10;fun();coutsetw(6)asetw(6)::aendl;return0;}213.4.4局部变量与栈•栈实现函数调用和局部变量的空间分配。例如:voidcat(intx){coutxendl;}voiddog(inta){intb=10;cat(b+a);}intmain(){inta=20;dog(a);coutaendl;return0;}223.5变量的存储类别•存储类别修饰符:auto、register、static和extern。(1)auto和register修饰自动存储变量;(2)static修饰静态存储变量;(3)extern修饰外部存储变量。233.5.1auto修饰的变量intfun(inta){autointb=2;……{doubled;……}}243.5.2register修饰的变量intfactor(intn){registerintf=1,i;for(i=1;i=n;i++)f*=i;returnf;}建议少用该修饰符。253.5.3static修饰的变量voidfun(){staticinta;//局部静态变量intb=1;a++;b++;coutasetw(6)bendl;}intmain(){for(inti=0;i5;i++)fun();return0;}263.5.4extern修饰的变量•extern扩展全局变量的作用域,表现为:(1)将全局变量的作用域扩展到定义它之前。1externintx,y;2intmin(inta,intb)3{returnab?a:b;4}5intmain()6{coutmin(x,y);7return0;8}9intx=3,y=5;//定义全局变量273.5.4extern修饰的变量•extern扩展全局变量的作用域,表现为:(2)将全局变量的作用域扩展到其他文件。//Ex3-a.cppintx=3,y=5;intmain(){coutadd();return0;}//Ex3-b.cppexternx,y;intadd(){returnx+y;}283.6默认参数•默认参数也称缺省参数。在函数调用中省略了函数实参,将把参数的缺省值赋给函数形参。•缺省值的设定通常是在函数原型中给出。voidshowArea(floatlength=20.0,floatwidth=10.0);voidshowArea(floatlength,floatwidth){floatarea=length*width;coutTheareaisareaendl;}?showArea();?showArea(12.0);?showArea(12.0,5.5);voiddisplayStars(int=10,int=1);intmain(){displayStars();coutendl;displayStars(5);coutendl;displayStars(7,3);return0;}voiddisplayStars(intcols,introws){for(intdown=0;downrows;down++){for(intacross=0;acrosscols;across++)cout*;coutendl;}}思考程序运行结果303.7引用作参数•C++支持按值传递、按引用传递。•引用不是定义一个新的变量,而是给一个已经定义过的变量重新取个名。•通过引用做参数,可以修改调用函数中的变量。例1:intx,&y=x;y=200;voiddoubleNum(int&);voidgetNum(int&);intmain(){intvalue;getNum(value);doubleNum(value);cout乘以2以后的结果是:valueendl;return0;}voidgetNum(int&userNum){cout请输入一个数:;cinuserNum;}voiddoubleNum(int&refVar){refVar*=2;}思考结果32如果函数具有多个引用参数,每个引用变量前加符号&。voidaddThree(int&,int&,int&,int&);voidaddThree(int&sum,int&n1,int&n2,int&n3){cout请输入三个整形值:;cinn1n2n3;sum=n1+n2+n3;}思考:如果函数f的形参是引用,主调函数m在调用f时,实参是一个值,可以吗?3.7引用作参数333.8函数重载•程序中定义多个函数,函数的名字相同,但参数的类型或个数不完全相同。intsquare(intnumber){returnnumber*number;}doublesquare(doublenumber){returnnumber*number;}intmain(){intuserInt;doubleuserDouble;cinuserIntuserDouble;coutsquare(userInt)和square(userDouble);}34注意1:不能采用函数返回值的类型来区别重载:intsquare(int);doublesquare(int);注意2:C++在进行函数调用时,不仅靠函数名识别函数,而且还要看参数列表。3.8函数重载【例3.11】计算员工的周薪。voidgetChoice(char&);doublecalcWeeklyPay(int,double);doublecalcWeeklyPay(double);intmain(){charselection;intworked;doublerate