《002_3C++研究生程序设计.ppt》由会员分享,可在线阅读,更多相关《002_3C++研究生程序设计.ppt(64页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C+程序设计程序设计第二章第二章 C+编程基础编程基础(三)(三)1/30/202312.3 函数函数函数概述函数的定义与声明函数的调用作用域1/30/202322.3.1 函数概述函数概述函数也称子程序、例程或过程,它是把一些相关函数也称子程序、例程或过程,它是把一些相关的语句组织在一起,用于解决某一特定问题的语的语句组织在一起,用于解决某一特定问题的语句块。句块。函数是函数是C+程序的基本特征,它将程序和代码进程序的基本特征,它将程序和代码进行了封装,实现了对程序设计的高级抽象。在行了封装,实现了对程序设计的高级抽象。在C+中常把一个程序分成多个函数来实现。这样中常把一个程序分成多个函数来
2、实现。这样设计的目的隐藏了具体实现的细节问题,而且还设计的目的隐藏了具体实现的细节问题,而且还是实现参数化和实现结构化的具体表现。函数抽是实现参数化和实现结构化的具体表现。函数抽象的实现,将有利于数据共享,节省开发时间,象的实现,将有利于数据共享,节省开发时间,增强程序的可靠性和便于管理等。增强程序的可靠性和便于管理等。1/30/202331、使用函数的优点、使用函数的优点(1)可读性好;)可读性好;(2)易于查错和修改;)易于查错和修改;(3)便于分工编写,分阶段调试;)便于分工编写,分阶段调试;(4)各各个个函函数数之之间间接接口口清清晰晰,便便于于相相互互间间交交换换信信息和使用;息和使
3、用;(5)节省程序代码和存储空间;)节省程序代码和存储空间;(6)减少用户总的工作量;)减少用户总的工作量;(7)成为实现结构程序设计思想的重要工具;)成为实现结构程序设计思想的重要工具;(8)扩充语言和计算机的原设计能力;)扩充语言和计算机的原设计能力;(9)便于验证程序正确性。)便于验证程序正确性。1/30/202342、main()函数函数设计设计C+程序的过程,实际上就是编写函数的过程序的过程,实际上就是编写函数的过程,至少要编写一个程,至少要编写一个main()()函数。函数。执行执行C+程序,也就是执行相应的程序,也就是执行相应的main()()函函数。即从数。即从main()()
4、函数的第一个左花括号函数的第一个左花括号“”开始,依次执行后面的语句,直到最后一个右花开始,依次执行后面的语句,直到最后一个右花括号括号“”为止。如果在执行过程中遇到其他的函为止。如果在执行过程中遇到其他的函数,则调用其他函数。调用完后,返回到刚才调数,则调用其他函数。调用完后,返回到刚才调用函数的下一条语句继续执行。而其他函数也只用函数的下一条语句继续执行。而其他函数也只有在执行有在执行main()()函数的过程中被调用时才会函数的过程中被调用时才会执行。执行。1/30/202352.3.2 函数的定义与声明函数的定义与声明函数分为系统函数和自定义函数两种。系统函数函数分为系统函数和自定义函
5、数两种。系统函数是是C+标准函数库中提供的可以在任何程序中使标准函数库中提供的可以在任何程序中使用的公共函数,使用系统函数必须指定函数所在用的公共函数,使用系统函数必须指定函数所在的包含文件,同样也适用于自定义函数库的调用。的包含文件,同样也适用于自定义函数库的调用。函数必须先定义才能使用。也就是说调用函数的函数必须先定义才能使用。也就是说调用函数的语句必须在函数定义或函数原型之后。为了方便语句必须在函数定义或函数原型之后。为了方便于程序设计,一般函数定义都放在一个函数文件于程序设计,一般函数定义都放在一个函数文件库中,在程序首部指定包含文件。库中,在程序首部指定包含文件。1/30/20236
6、1、函数的定义、函数的定义C+中中的的每每一一个个函函数数都都是是从从四四个个方方面面来来进进行行定定义义:类型、函数名、形式参数表、函数体。类型、函数名、形式参数表、函数体。定义一个函数的语法格式为:定义一个函数的语法格式为:类型类型 函数名(形式参数表)函数名(形式参数表)函数体;函数体;函数的定义不允许嵌套。函数的定义不允许嵌套。1/30/20237函数定义的说明:函数定义的说明:(1)类型就是该函数的类型,也就是该函数的返回)类型就是该函数的类型,也就是该函数的返回值的类型,此类型可以是值的类型,此类型可以是C+中除函数、数组类中除函数、数组类型之外的任何一个合法的数据类型,包括普通类
7、型之外的任何一个合法的数据类型,包括普通类型、指针类型和引用类型等。型、指针类型和引用类型等。(2)函数的返回值通常指明了该函数处理的结果,)函数的返回值通常指明了该函数处理的结果,由函数体中的由函数体中的return语句给出。一个函数可以有语句给出。一个函数可以有返回值,也可以无返回值(称为无返回值函数或返回值,也可以无返回值(称为无返回值函数或无类型函数)。此时需要使用保留字无类型函数)。此时需要使用保留字void作为类作为类型名,而且函数体中也不需要再写型名,而且函数体中也不需要再写return语句,语句,或者或者return的后面什么也没有。的后面什么也没有。(3)每个函数都有类型,如
8、果在函数定义时没有明)每个函数都有类型,如果在函数定义时没有明确指定类型,则默认类型为确指定类型,则默认类型为int。1/30/20238(4)函数名是一个有效的)函数名是一个有效的C+标识符,遵标识符,遵循一般的命名规则。在函数名后面必须跟循一般的命名规则。在函数名后面必须跟一对小括号一对小括号“()()”,用来将函数名与变,用来将函数名与变量名或其他用户自定义的标识符区分开来。量名或其他用户自定义的标识符区分开来。在小括号中可以没有任何信息,也可以包在小括号中可以没有任何信息,也可以包含形式参数表。含形式参数表。C+程序通过使用这个函数程序通过使用这个函数名和实参表可以调用该函数。名和实参
9、表可以调用该函数。1/30/20239(5)形式参数表又称参数表,写在函数名后面的一)形式参数表又称参数表,写在函数名后面的一对圆括号内。它可包含任意多个(含对圆括号内。它可包含任意多个(含0个,即没个,即没有)参数说明项,当多于一个时其前后两个参数有)参数说明项,当多于一个时其前后两个参数说明项之间必须用逗号分开。说明项之间必须用逗号分开。(6)每个参数说明项由一种已定义的数据类型和一)每个参数说明项由一种已定义的数据类型和一个变量标识符组成,该变量标识符称为该函数的个变量标识符组成,该变量标识符称为该函数的形式参数,简称形参,形参前面给出的数据类型形式参数,简称形参,形参前面给出的数据类型
10、称为该形参的类型。每个形参的类型可以为任一称为该形参的类型。每个形参的类型可以为任一种数据类型,包括普通类型、指针类型、数组类种数据类型,包括普通类型、指针类型、数组类型、引用类型等。型、引用类型等。1/30/202310(7)一个函数定义中的)一个函数定义中的可以被省略,表可以被省略,表明该函数为无参函数,若明该函数为无参函数,若用用void取代,取代,则也表明是无参函数,若则也表明是无参函数,若不为空,同不为空,同时又不是保留字时又不是保留字void,则称为带参函数。则称为带参函数。(8)是一条复合语句,它以左花括号开是一条复合语句,它以左花括号开始,到右花括号结束,中间为一条或若干条始,
11、到右花括号结束,中间为一条或若干条C+语句,用于实现函数执行的功能。语句,用于实现函数执行的功能。(9)在一个函数体内允许有一个或多个)在一个函数体内允许有一个或多个return语语句,一旦执行到其中某一个句,一旦执行到其中某一个return语句时,语句时,return后面的语句就不再执行,直接返回调用位后面的语句就不再执行,直接返回调用位置继续向下执行。置继续向下执行。1/30/202311例如:看下面是几个函数及返回类型。例如:看下面是几个函数及返回类型。(1)获取参数并返回值获取参数并返回值 int bigger(int a,int b)return(ab)?a:b (2)获取参数但不返
12、回值获取参数但不返回值 void delay(long a)for (int i=1;i=a;i+);/时间延时间延迟迟 1/30/202312(3)没有获取参数但返回值没有获取参数但返回值 int geti()int x;cout x;return x;(4)没有获取参数也不返回值没有获取参数也不返回值 void message()cout b)t=a;elset=b;returnt;voidmain()cout“Input two data:”xxy;coutmax(x,y)endl;1/30/2023142、函数的声明、函数的声明函函数数声声明明也也称称函函数数原原型型。函函数数原原型型
13、类类似似函函数数定定义义时时的的函函数数头头。为为了了能能使使函函数数在在定定义义之之前前就就能能被被调调用用,C+规规定定可可以以先先说说明明函函数数原原型型,然然后后就就可可以以调用函数。函数定义可放在程序后面。调用函数。函数定义可放在程序后面。由于函数原型是一条语句,因此函数原型必须以由于函数原型是一条语句,因此函数原型必须以分号结束。函数原型由函数返回类型、函数名和分号结束。函数原型由函数返回类型、函数名和参数表组成,它与函数定义的返回类型、函数名参数表组成,它与函数定义的返回类型、函数名和参数表必须一致。函数原型不必包含参数的名和参数表必须一致。函数原型不必包含参数的名字,可只包含参
14、数的类型。字,可只包含参数的类型。1/30/202315例如:例如:int area(int,int);等价于等价于 int area(int a,int b););说明:系统标准函数并没有在包含文件中说明:系统标准函数并没有在包含文件中定义,而只是提供了函数原型。在调用函定义,而只是提供了函数原型。在调用函数时,系统会正确地调用库函数。数时,系统会正确地调用库函数。注意:函数原型与函数定义必须一致,否注意:函数原型与函数定义必须一致,否则会引起编译错误。则会引起编译错误。1/30/202316例例2.3-2 求任意三角形的面积求任意三角形的面积#include iostream.h#incl
15、ude math.h“float triangle_area(float,float,float);void print();void main()float a,b,c,area;coutabc;if(a+bc&a+cb&b+ca)area=triangle_area(a,b,c);coutarea=areaendl;elseprint();float triangle_area(float x,float y,float z)float p,s;p=(x+y+z)/2;s=sqrt(p*(p-x)*(p-y)*(p-z);return s;void print()coutInput err
16、or!endl;1/30/2023172.3.3 函数的调用函数的调用1、函数调用格式:、函数调用格式:在在C+中中,除除了了主主函函数数main由由系系统统自自动动调调用用外外,其其他他函函数数都都是是由由主主函函数数直直接接或或间间接调用的。函数调用的语法格式为:接调用的。函数调用的语法格式为:函数名函数名(实际参数表);(实际参数表);实参应该与函数定义中的形参表中的形参实参应该与函数定义中的形参表中的形参一一对应,即个数相等、次序一致且对应一一对应,即个数相等、次序一致且对应参数的数据类型相同或相容参数的数据类型相同或相容。每个实参是。每个实参是一个表达式,并且必须有确定的值。一个表达
17、式,并且必须有确定的值。1/30/202318例如:例如:g1(25)/实参是一个整数实参是一个整数g2(x)/实参是一个变量实参是一个变量g3(a,2*b+3)/第一个为变量,第二个是算术表达式第一个为变量,第二个是算术表达式g4(sin(x),)/第一个为函数调用表达式,第二第一个为函数调用表达式,第二/个为字符常量个为字符常量g5(&d,*p,x/y-1)/分别为取地址运算、间接访问和分别为取地址运算、间接访问和/一般算术表达式一般算术表达式 1/30/202319函数调用方式:函数调用方式:常见的函数调用方式有下列两种:常见的函数调用方式有下列两种:方方式式一一:将将函函数数调调用用作
18、作为为一一条条表表达达式式语语句句使使用用,只只要要求求函函数数完完成成一一定定的的操操作作,而而不不使使用用其其返返回回值值。若若函函数数调调用用带带有有返回值,则这个值将会自动丢失。例如:返回值,则这个值将会自动丢失。例如:max(3,5);方方式式二二:对对于于具具有有返返回回值值的的函函数数来来说说,把把函函数数调调用用语语句句看看作作语语句句一一部部分分,使使用用函函数数的的返返回回值值参参与与相相应应的的运运算算或或执执行行相应的操作。例如:相应的操作。例如:inta=max(3,5);inta=max(3,5)+1;coutmax(3,5)endl;if(f1(a,b)cout”
19、true”endl;inta=2;a=max(max(a,3),5);1/30/2023202、函数调用过程、函数调用过程当调用一个函数时,整个调用过程分为三当调用一个函数时,整个调用过程分为三步进行,第一步是参数传递,第二步是函步进行,第一步是参数传递,第二步是函数体执行,第三步是返回,即返回到函数数体执行,第三步是返回,即返回到函数调用表达式的位置或函数调用语句的下一调用表达式的位置或函数调用语句的下一条语句。条语句。1/30/2023213、函数的调用机制、函数的调用机制函数调用对用户来讲非常简单,但实际上为了在调用函数函数调用对用户来讲非常简单,但实际上为了在调用函数后能正确地使用函数
20、参数和正确地返回到调用时的位置,后能正确地使用函数参数和正确地返回到调用时的位置,必须将一些数据存储在栈中。这个处理过程称为函数调用必须将一些数据存储在栈中。这个处理过程称为函数调用机制。机制。栈在函数调用过程中具有非常重要的作用。栈在函数调用过程中具有非常重要的作用。函数调用时,函数调用时,C+需要做下面一些工作:需要做下面一些工作:建立被调函数的栈空间建立被调函数的栈空间保护调用函数的运行状态和返回地址保护调用函数的运行状态和返回地址保护函数传递的参数保护函数传递的参数将控制转交被调函数将控制转交被调函数栈空间主要由函数内部定义的变量和函数参数所占用,由栈空间主要由函数内部定义的变量和函数
21、参数所占用,由于系统默认栈空间是有限制的,因此,当需要较多的内存于系统默认栈空间是有限制的,因此,当需要较多的内存空间时则必须在连接前设置栈空间大小。空间时则必须在连接前设置栈空间大小。1/30/2023224、函数调用时的参数传递、函数调用时的参数传递参数传递称为参数传递称为“实虚结合实虚结合”,即实参向形,即实参向形参传递信息,使形参具有确切地含义(即参传递信息,使形参具有确切地含义(即具有对应的存储空间和初值)。这种传递具有对应的存储空间和初值)。这种传递又分为两种不同的方式,一种是按值传递,又分为两种不同的方式,一种是按值传递,另一种是地址传递或引用传递。另一种是地址传递或引用传递。1
22、/30/202323(1)按值传递按值传递以按值传递方式进行参数传递的过程为:首先计以按值传递方式进行参数传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型配一个存储空间,该空间的大小等于该形参类型的长度,然后把已求出的实参表达式的值一一存的长度,然后把已求出的实参表达式的值一一存入到为形参变量分配的存储空间中,成为形参变入到为形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故是把实参表达
23、式的值传送给对应的形参变量,故称这种传递方式为称这种传递方式为“按值传递按值传递”。这种方式被调。这种方式被调用函数本身不对实参进行操作,也就是说,即使用函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。不会受到影响,仍为调用前的值。1/30/202324例例2.3-3 交换两个变量的值(按值传递)交换两个变量的值(按值传递)#includeiostream.hvoidswap(int,int);voidmain()inta=3,b=4;couta=a,b=“bendl;swap(a,b);
24、couta=a,b=bendl;voidswap(intx,inty)intt=x;x=y;y=t;此程序的运行结果为:此程序的运行结果为:a=3,b=4a=3,b=41/30/202325(2)地址传递)地址传递如果在函数定义时将形参的类型说明成指针,对如果在函数定义时将形参的类型说明成指针,对这样的函数进行调用时就需要指定地址值形式的这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式即为地址传递方式。实参。这时的参数传递方式即为地址传递方式。这种地址传递与上述的按值传递不同,它把实参这种地址传递与上述的按值传递不同,它把实参的存储地址传送给对应的形参,从而使得形参指的存储地
25、址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变数中对形参指针所指向的地址中内容的任何改变都会影响到实参。都会影响到实参。1/30/202326例例2.3-4 交换两个变量的值(按地址传递)交换两个变量的值(按地址传递)#includeiostream.hvoidswap(int*,int*);voidmain()inta=3,b=4;couta=a,b=“bendl;swap(&a,&b);couta=a,b=“bendl;voidswap(int*x,int*y)intt=*x;
26、*x=*y;*y=t;此程序的运行结果为:此程序的运行结果为:a=3,b=4a=4,b=31/30/202327(3)引用传递)引用传递按值传递方式容易理解,但形参值的改变不能对按值传递方式容易理解,但形参值的改变不能对实参产生影响;地址传递方式虽然可以使得形参实参产生影响;地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误利用指针进行间接访问,会使程序容易产生错误且难以阅读。如果以引用作为参数,则既可以使且难以阅读。如果以引用作为参数,则既可以使得对形参的任何操作都能改变相应的实参的数据,
27、得对形参的任何操作都能改变相应的实参的数据,又使函数调用显得方便、自然。引用传递方式是又使函数调用显得方便、自然。引用传递方式是在函数定义时在形参前面加上引用运算符在函数定义时在形参前面加上引用运算符“&”(引用通常被认为是另一个变量的别名,通过别(引用通常被认为是另一个变量的别名,通过别名可直接访问这个变量)。名可直接访问这个变量)。1/30/202328例例2.3-5 交换两个变量的值(引用传递)交换两个变量的值(引用传递)#includeiostream.hvoidswap(int&,int&);voidmain()inta=3,b=4;couta=a,b=“bendl;swap(a,b
28、);couta=a,b=“bendl;voidswap(int&x,int&y)intt=x;x=y;y=t;此程序的运行结果为:此程序的运行结果为:a=3,b=4a=4,b=31/30/2023295、内联函数、内联函数(1)内联函数的意义)内联函数的意义内联扩展(内联扩展(inline expansion)简称为内联简称为内联(inline),),内联函数也称为内嵌函数。当在一个函数的内联函数也称为内嵌函数。当在一个函数的定义或声明前加上关键字定义或声明前加上关键字inline则就把该函数定义为内联则就把该函数定义为内联函数,它主要是解决程序的运行效率。函数,它主要是解决程序的运行效率。计
29、算机在执行一般函数的调用时,无论该函数多么简单或计算机在执行一般函数的调用时,无论该函数多么简单或复杂,都要经过参数传递、执行函数体和返回等操作,这复杂,都要经过参数传递、执行函数体和返回等操作,这些操作都需要一定的时间开销。若把一个函数定义为内联些操作都需要一定的时间开销。若把一个函数定义为内联函数后,在程序编译阶段,编译器就会把每次调用该函数函数后,在程序编译阶段,编译器就会把每次调用该函数的地方都直接替换为该函数体中的代码,由此省去函数的的地方都直接替换为该函数体中的代码,由此省去函数的调用及相应的保存现场、参数传递和返回操作,从而加快调用及相应的保存现场、参数传递和返回操作,从而加快整
30、个程序的执行速度。整个程序的执行速度。1/30/202330(2)内联函数的实现)内联函数的实现定义内联函数的方法很简单。只要在函数定义内联函数的方法很简单。只要在函数定义的头前面加上关键字定义的头前面加上关键字inline即可。其即可。其它与函数定义相同。例如:它与函数定义相同。例如:inline int add_int(int x,int y,int z)return x+y+z;这里这里add_int就是一个内联函数。就是一个内联函数。1/30/202331(3)内联函数的声明)内联函数的声明与其它函数一样,内联函数必须先声明后与其它函数一样,内联函数必须先声明后使用,如果要声明一个内联
31、函数原型,则使用,如果要声明一个内联函数原型,则也必须加上声明关键字也必须加上声明关键字inline。例如:例如:inline int add_int(int x,int y,int z);/函数原型函数原型1/30/202332(4)内联函数的限制)内联函数的限制内联函数虽然具有普通函数的特性,但其处理方内联函数虽然具有普通函数的特性,但其处理方式与普通函数不同,它是将调用表达式用内联函式与普通函数不同,它是将调用表达式用内联函数体来替换,若内联函数比较大,在程序中就会数体来替换,若内联函数比较大,在程序中就会有多个程序备份,反而会占用更多的内存空间,有多个程序备份,反而会占用更多的内存空间
32、,这就失去了内联函数存在的实际意义。因此,这就失去了内联函数存在的实际意义。因此,C+对内联函数的定义有专门限制。对内联函数的定义有专门限制。在内联函数内部不允许使用循环语句和开关语句,否在内联函数内部不允许使用循环语句和开关语句,否则系统将其视为普通函数。则系统将其视为普通函数。内联函数不能是递归函数。内联函数不能是递归函数。语句数尽可能少,一般不超过语句数尽可能少,一般不超过5行。行。1/30/202333例例2.3-6 用内联函数实现求某数的绝对值用内联函数实现求某数的绝对值#includeiostream.hinlineintabs(intx)returnx0?-x:x;voidmai
33、n()inta,b=3,c,d=-4;a=abs(b);c=abs(d);couta=a,c=cendl;此程序的运行结果为:此程序的运行结果为:a=3,c=41/30/2023346、重载函数、重载函数(1)函数重载的意义)函数重载的意义所谓函数重载是指同一个函数名可以对应着多所谓函数重载是指同一个函数名可以对应着多个函数的实现。例如,可以给函数名个函数的实现。例如,可以给函数名add()()定义多个函数实现,该函数的功能是求和,即定义多个函数实现,该函数的功能是求和,即求两个操作数的和。其中,一个函数是求两个求两个操作数的和。其中,一个函数是求两个int型的和,另一个实现是求两个浮点型数之
34、和。型的和,另一个实现是求两个浮点型数之和。每种实现都对应一个函数体,这些函数的名字每种实现都对应一个函数体,这些函数的名字相同,但是函数的参数的类型不同。这就是函相同,但是函数的参数的类型不同。这就是函数重载的概念。数重载的概念。1/30/202335例例2.3-7 求两个操作数之和。求两个操作数之和。#include int add(int,int);double add(double,double);void main()coutadd(5,10)endl;coutadd(5.0,10.5)endl;int add(int x,int y)return x+y;double add(do
35、uble a,double b)return a+b;1/30/202336例例2.3-8 找出几个找出几个int型中的最小值型中的最小值#include int min(int a,int b);int min(int a,int b,int c);int min(int a,int b,int c,int d);void main()cout min(13,5,4,9)endl;int min(int a,int b)return ab?a:b;int min(int a,int b,int c)int t=min(a,b);return min(t,c);int min(int a,in
36、t b,int c,int d)int t1=min(a,b,c);return min(t1,d);1/30/202337(2)函数重载的匹配)函数重载的匹配调用一个重载函数时,编译器是如何知道该调用调用一个重载函数时,编译器是如何知道该调用那个函数呢?这就要根据实参和形参类型以及参那个函数呢?这就要根据实参和形参类型以及参数的个数来决定。具体比较过程:数的个数来决定。具体比较过程:寻找一个严格的匹配,如果找到了,就用那个函数。寻找一个严格的匹配,如果找到了,就用那个函数。这种匹配要求类型一致、参数个数一致。这种匹配要求类型一致、参数个数一致。通过内部转换寻求一个匹配,只要找到了,就用那个通
37、过内部转换寻求一个匹配,只要找到了,就用那个匹配。这种要求参数个数一致,类型可内部转换实现。匹配。这种要求参数个数一致,类型可内部转换实现。通过用户定义的转换条件寻求匹配,若能查出有唯一通过用户定义的转换条件寻求匹配,若能查出有唯一的一组转换,就用那个函数。的一组转换,就用那个函数。1/30/2023387、默认参数、默认参数(1)默认参数的含义)默认参数的含义默认参数就是在调用函数时可以省略实参。例如:默认参数就是在调用函数时可以省略实参。例如:void delay(int loops);.void delay(int loops)if(loops=0)return;for(int i=0;
38、iloops;i+);这是一个时间延迟函数,调用该函数时必须指出参数。如果想要默认延迟这是一个时间延迟函数,调用该函数时必须指出参数。如果想要默认延迟为为loops的值为的值为1000,则在函数声明时为,则在函数声明时为loops指定一个默认值即可。指定一个默认值即可。void delay(int loops=1000);这样调用时可以指定或省略参数。例如:这样调用时可以指定或省略参数。例如:delay(3000);delay();1/30/202339(2)默认参数的声明规定)默认参数的声明规定注意:当函数既有声明又有定义时,默认注意:当函数既有声明又有定义时,默认参数在函数声明中定义,函数
39、定义中不允参数在函数声明中定义,函数定义中不允许使用默认参数。只有当函数没有声明时,许使用默认参数。只有当函数没有声明时,才可以在函数定义中指定形参的默认值。才可以在函数定义中指定形参的默认值。1/30/202340(3)默认参数的顺序规定)默认参数的顺序规定当函数中定义默认参数时,如果仅有部分参数定义成默认当函数中定义默认参数时,如果仅有部分参数定义成默认参数,则应将默认参数连续放在右边参数,则应将默认参数连续放在右边(不能空缺不能空缺)。当调用。当调用函数时只能向左匹配参数。函数时只能向左匹配参数。例如:例如:void func(int a=1,int b,int c=3,int d=4)
40、;/错错 void func(int a,int b=2,int c=3,int d=4);/正正确确对于第二个声明,其调用的方法为:对于第二个声明,其调用的方法为:func(10,15,20,30);/正确正确 func();/错误错误 func(12,12);/正确,参数正确,参数c,d默认默认 func(2,15,20);/错误,只能从右到左顺序匹配错误,只能从右到左顺序匹配默认参数,这等于将默认参数,这等于将c进行默认匹配,而没有将进行默认匹配,而没有将d也默认也默认匹配,也就是说,匹配,也就是说,c默认匹配则默认匹配则d也必须先默认匹配。也必须先默认匹配。1/30/202341(3)
41、默认参数与函数重载)默认参数与函数重载默认参数可将一系列简单的重载函数合成为一个。例如,默认参数可将一系列简单的重载函数合成为一个。例如,下面三个重载函数:下面三个重载函数:void point(int,int);void point(int a)return point(a,4);void point()return point(3,4);可以合成为下面带有默认参数的函数可以合成为下面带有默认参数的函数 void point(int=3,int=4);/函数原型,可省略函数原型,可省略形式参数名。下面调用是合法的。形式参数名。下面调用是合法的。point();/调用调用point(3,4),
42、等于调用上面第三个等于调用上面第三个函数函数 point(6);/调用调用point(6,4),等于调用上面第二等于调用上面第二个函数个函数 point(7,8);/调用调用 point(7,8),等于调用上面第一等于调用上面第一个函数个函数1/30/202342(4)默认值的限定)默认值的限定形形参参的的默默认认值值可可以以是是全全局局常常量量、全全局局变变量量、表表达达式、函数调用,但不能为局部变量。式、函数调用,但不能为局部变量。例如,下例不合法:例如,下例不合法:voidfunc1()intk;voidg(intx=k);/k为局部变量为局部变量 1/30/2023438、函数的嵌套调
43、用、函数的嵌套调用由前述可知,由前述可知,C+函数不能嵌套定义,即一个函数不能函数不能嵌套定义,即一个函数不能在另一个函数体中进行定义。但在使用时,允许嵌套调用,在另一个函数体中进行定义。但在使用时,允许嵌套调用,即在调用一个函数的过程中又调用另一个函数。即在调用一个函数的过程中又调用另一个函数。例如:例如:func1(inta,floatb)floatc;c=func2(b-1,b+1);intfunc2(floatx,floaty)函数体函数体func1和和func2是分别独立定义的函数,互不从属。是分别独立定义的函数,互不从属。1/30/2023449、递归函数、递归函数(1)递归概念)
44、递归概念一个函数直接或间接地调用自身,这种现象就是一个函数直接或间接地调用自身,这种现象就是函数的递归调用。函数的递归调用。递归调用有两种方式:直接递归调用和间接递归递归调用有两种方式:直接递归调用和间接递归调用。直接递归调用即在一个函数中调用自身,调用。直接递归调用即在一个函数中调用自身,间接递归调用即在一个函数中调用了其他函数,间接递归调用即在一个函数中调用了其他函数,而在该其他函数中又调用了本函数。而在该其他函数中又调用了本函数。利用函数的递归调用,可将一个复杂问题分解为利用函数的递归调用,可将一个复杂问题分解为一个相对简单且可直接求解的子问题(一个相对简单且可直接求解的子问题(“递推递
45、推”阶段);然后将这个子问题的结果逐层进行回代阶段);然后将这个子问题的结果逐层进行回代求值,最终求得原来复杂问题的解(求值,最终求得原来复杂问题的解(“回归回归”阶阶段)。段)。1/30/202345例例2.3-9 用递归方法求用递归方法求n的阶乘的阶乘#includeiostream.hlongf(intn)if(n0)cout“error!“endl;return(-1);elseif(n=1)return(1);elsereturn(n*f(n-1);voidmain()longf(intn);intn;coutpleaseinputn:“n;coutn!=f(n)2时时假定求出第八项
46、。假定求出第八项。分析:分析:Fibonacci数列的计算具备递归的条件。数列的计算具备递归的条件。首先有递推公式首先有递推公式F(n)=F(n-1)+F(n-2),),第二有结束递归的条件即第二有结束递归的条件即n=0或或n=1时不再递归。时不再递归。1/30/202348例例2.3-10 程序程序#include const N=8;long fibo(int n);void main()long f=fibo(N);coutfendl;long fibo(int n)if(n=1)return 1L;else if(n=2)return 1L;else return fibo(n-1)+
47、fibo(n-2);程序执行结果如下:程序执行结果如下:211/30/202349(3)递归的评价与消除递归)递归的评价与消除递归递归程序虽然易读、易编,但需要占用额递归程序虽然易读、易编,但需要占用额外的内存空间,并且执行速度也受影响。外的内存空间,并且执行速度也受影响。是否利用递归编程要看实际问题,如果要是否利用递归编程要看实际问题,如果要节约内存就用循环语句实现。若对内存要节约内存就用循环语句实现。若对内存要求并不高,用递归编程会更好。求并不高,用递归编程会更好。1/30/2023502.3.4 作用域作用域作用域又称作用范围。标识符只能在说明作用域又称作用范围。标识符只能在说明它或定义
48、它的范围内是可见的(可以进行它或定义它的范围内是可见的(可以进行存取或访问操作),而在该范围之外是不存取或访问操作),而在该范围之外是不可见的(不可以进行存取和访问操作)。可见的(不可以进行存取和访问操作)。在程序中出现的各种标识符,它们的作用在程序中出现的各种标识符,它们的作用范围是不同的。这里讲的范围有大有小,范围是不同的。这里讲的范围有大有小,最大的是整个程序,最小的是块,中间有最大的是整个程序,最小的是块,中间有文件和函数。文件和函数。1/30/2023511、作用域的种类、作用域的种类程序级。作用域最大,它包含着组成该程序的所程序级。作用域最大,它包含着组成该程序的所有文件。包括外部
49、函数和外部变量。有文件。包括外部函数和外部变量。文件级。包括内部函数和外部静态变量。仅在定文件级。包括内部函数和外部静态变量。仅在定义它的文件内有效。义它的文件内有效。函数级。包括函数的形参、函数内定义的自动类函数级。包括函数的形参、函数内定义的自动类变量和内部静态类变量以及语句标号。在它定义变量和内部静态类变量以及语句标号。在它定义的函数体内有效。的函数体内有效。块级。包括定义在分程序中、块级。包括定义在分程序中、if语句中、语句中、switch语句中以及循环语句中的自动类变量和内部静态语句中以及循环语句中的自动类变量和内部静态变量。作用域从定义位置开始至块结束为止。变量。作用域从定义位置开
50、始至块结束为止。1/30/2023522、关于重新定义标识符的作用域规定、关于重新定义标识符的作用域规定在在C+中,一般地说,变量不能重复定义,这是指相同的作用域内,中,一般地说,变量不能重复定义,这是指相同的作用域内,不可有同名变量存在。但在不同的作用域内,允许对某个变量重新定不可有同名变量存在。但在不同的作用域内,允许对某个变量重新定义。例如,下列程序段是合法的。义。例如,下列程序段是合法的。void fun()int a;/在整个在整个fun()函数中有效函数中有效 float a;/只在此分程序内有效,而只在此分程序内有效,而int a此时隐藏起来,此时隐藏起来,/出了分程序后再显现出