第 5章 函数与预处理
教学提示:函数(Function)是 C++的一个重要组成部分,从外部看,它就像一个好的帮
手,能够独立完成一件特殊的工作,然后将工作后的结果带回来;从内部看,它实质上是
将一条一条的语句有机地结合到一起,为了完成更复杂的任务,在语句序列中,还可以使
用其他函数,有时为了特殊需要,还可以使用其自己。通过这些函数的
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
,使得一些松
散的语句组合成能够完成一项特殊任务的逻辑整体——模块,将这些模块再进行有机组合,
就可以构成能够解决复杂任务的统一体——程序。在 C++程序设计中,函数不仅是模块划
分的基本单位,还是处理问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
的基本过程抽象单元,而且函数也为代码的重用提供了技术
上的支持。
学习目标:
z 掌握函数的定义格式和函数的原型声明方法;
z 掌握函数的调用方法以及形式参数和实际参数之间的关系;
z 掌握函数的嵌套和递归调用使用方法;
z 掌握内联函数和函数重载的使用方法;
z 了解函数的作用域与生命期;
z 了解编译预处理的基本原理和使用方法。
5.1 函数的定义
5.1.1 函数的定义格式
C++中的每一个函数都由 4 部分构成:类型、函数名、参数表和函数体。定义一个函
数的语法格式为:
<类型名> <函数名> ([<参数表>]) <函数体>
例如:
int min(int a,int b)
{
int t;
if(a
是函数执行过程中通过 return 语句要求返回的值的类型,又称为函数的类型
或返回类型,它可以是系统或用户已定义的任何一种数据类型,省略时代表返回 int 型数据
C++程序设计
·116·
·116·
(强烈建议不要省略),当为 void 类型时,表示不返回任何值。
<函数名>可以是任意一个合法的标识符,在符合 C++标识符的一般命名规则的同时,
应尽量使其“见名知义”。在需要的时候,用户通过使用这个函数名和实参表可以调用该
函数。
<参数表>在函数定义的时候又称作形式参数表,简称形参。它包含有任意多个(含 0 个)
参数说明项,当多于一个时其前后两个参数说明项之间必须用逗号分开。
<函数体>可以为空,可以是一条单语句,但一般都是复合语句,它从左花括号开始,
到右花括号结束,中间为一条或若干条 C++语句。
在定义有参数的函数时,通常在函数头部的参数表中指定每个参数的类型和名称,如
前例所示的 min 函数的头部,另外,也可写成如下传统的格式:
int min(a,b)
int a;
int b;
{
······
······
}
5.1.2 函数的原型声明
在 C++中,如果一个函数要调用另一个函数,则需在本函数(称为主调函数)的定义之
前将要被调用的函数事先进行声明。函数的原型声明,简称函数声明,目的是提前告诉编
译器函数的返回类型、名称和形参表,以便编译时系统对函数的调用进行有效性检查。
函数原型的声明形式是:
<类型><被调用函数名>([<形参表>]);
例如,如果 printmin 函数要通过调用 min 函数来打印两个整数的最小值,则需要在
printmin 函数定义前进行如下的函数原型声明:
int min(int a,int b); //一定要注意末尾有个分号
以下是关于函数声明的几点说明。
(1) 一个完整的程序中,函数的定义和函数的调用可以在同一个程序文件中,也可以
处在不同的程序文件中,但必须确保函数声明语句与函数调用表达式出现在同一个文件中,
并且函数声明语句出现在前,函数的调用出现在后。
(2) 当一个函数要被一个文件中的多个函数调用时,必须将该函数声明写在所有函数
之前。
(3) 虽然函数声明与函数头相似,但是它们之间也有细微的差别,尤其是函数声明是
一条语句,末尾需要分号。
(4) 在函数声明的形参表中不能只写形参名而不写类型名,但可以只写类型名而不写
形参名。
(5) 由于函数调用时是按参数顺序进行传递的,所以函数声明中形参的次序不要写错。
(6) 如果被调用的函数其定义位于主调函数之前,则可以省略被调用函数的原型声明。
第 5章 函数与预处理
·117·
·117·
5.2 函数的调用和参数
5.2.1 函数的调用
函数调用是一个 C++程序各部分能够形成一个有机整体的重要机制。函数调用的格
式为:
<函数名>([<实参表>])
关于函数调用有以下几点说明。
(1) 前面说过,定义函数时的参数称为形式参数或称形参,与之相对应,调用函数时
的参数称为实际参数或称实参。
(2) 函数可以不带有任何的实际参数,但是如果有,就必须要与函数定义时形参的个
数及类型完全一致。
(3) 以函数在程序中的出现位置和形式来看,函数的调用方式可分为以下 3 种。
① 函数调用作为独立语句,例如:
showColor();
这种方式调用的函数一般是完成某项功能,没有任何的返回值。
② 函数作为表达式的一部分,例如:
number=max(numA,numB)/2;
这是函数调用中最常使用的一种方式。
③ 函数的调用以实参形式出现在被调用的函数中。例如:
number=min(sum(-5,100),numC);
函数 sum 在这里作为函数 min 的一个实参。
(4) 一个函数调用的执行过程可以分为以下 3 个处理阶段。
① 首先把实参值传入被调用函数形参的对应单元中,中断主调函数当前的执行,并且
保存返回地点(称为断点)。
② 执行被调用函数语句,直到执行 return 语句以返回。若被调用函数中没有 return 语
句,则直到其全部语句执行完毕后自动返回到位于主调函数中的断点处。
③ 从保存的断点处,主调函数继续执行其他剩余语句。
【例 5.1】 编写程序,通过函数调用实现学生数学课的成绩等级输出。要求成绩在 90~
100 之间为 A 级,80~89 之间为 B 级,70~79 之间为 C 级,60~79 之间为 D 级,其余的
为 E 级。
//程序名为 ch05_1.cpp:
#include
void ShowGrade(char name[ ], float score); //函数原型声明
main( )
{
char studentName[10];
C++程序设计
·118·
·118·
float mathScore;
cout<<"Please input the name and his/her math score !"<>studentName>>mathScore;
ShowGrade(studentName,mathScore); //函数调用
return 0;
}
void ShowGrade(char name[ ], float score)
{
if ((score>100 )||(score<0))
cout<<"You inputted a wrong score ! "<=90)
cout<<"Grade of "<=80)
cout<<"Grade of "<=70)
cout<<"Grade of "<=60)
cout<<"Grade of "< <形参 1>=<表达式 1>,…,<类型> <形参 n>=<表达式 n>
例如:
void draw(int x,int y,int color=BLACK); //假如 BLACK、RED等为某枚举
//元素的值,下同
关于带默认值的函数有以下几点说明。
(1) 默认值必须按从右向左的顺序声明,即在有默认值的参数右侧不能再出现无默认
值的形参。因此,以下两个函数原型都是错误的:
void draw(int x=0,int y,int color=BLACK); //错误!
void draw(int x=0,int y=0,int color); //错误!
(2) 一般应在函数的原型声明中依次列出参数的默认值,在函数定义时就不必再指定
参数的默认值。如果函数先定义后调用,则可以在定义函数时声明参数的默认值。
(3) 函数调用时,若省略某个实参而使形参采用默认值,则其后的实参都应省略。例
如,如果有:
void draw(int x=0,int y=0,int color=BLACK);
则正确和错误的函数调用有:
draw( ,10,RED); //错误!省略第 1个实参后,其后的第 2、3个都应省略
draw(10, ,RED); //错误!省略第 2个实参后,其后的第 3个实参必须省略
draw(10,10); //正确!第 3个参数取默认值 BLACK
【例 5.5】 编写具有默认参数值的函数实现求 3 个整数的和。
//程序名为 ch05_5.cpp:
#include
int add(int x=1,int y=2,int z=3); //函数原型声明形参及其默认值
void main(void)
{
int sum1,sum2,sum3;
sum1=add(10,20,30);
cout<<"sum1="<
float sum(float x, float y, float z);
float average(float a, float b, float c);
main( )
{
float num1,num2,num3;
cout<<"Please input the scores of the three courses !"
cin>>num1>>num2>>num3;
cout<<"The average score of the three course is "
<< average(num1,num2,num3)<=1 时
n!=
C++程序设计
·124·
·124·
这个公式很明显带有递归的思想,用递归程序书写也就会显得简单清晰。
【例 5.7】 编程计算 n!
//程序名为 ch05_7.cpp:
#include
long fac(int n)
{
long result;
if (n==0)
result=1;
else
result=n* fac(n-1);
return(result);
}
void main( )
{
int n;
cout<<"Plese input an integer number!"
cin>>n;
cout<
long fibonacci(long);
int main( )
{
long number,nthFibonacci;
cout<<"Please input the desired Fibonacci number to be determined ---->"
<>number;
cout<
20
The 20th Fibonacci number is : 6765
5.4 内联函数和重载函数
5.4.1 内联函数
使用 C++编写程序时,采用函数调用的方式来解决问题符合软件工程学的要求,是一
种好方法。我们既可以自己编写函数,也可以使用系统预定义的
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
库函数。但是,在程
序运行过程中,函数调用会增加时间开销,尤其对于那些经常使用的小函数。为此,C++
语言提供了内联函数来减少函数调用的开销。当在一个函数的定义或声明前加上关键字
inline,则就可以把该函数定义为内联函数。若把一个函数定义为内联函数后,在程序编译
阶段,编译器就会把每次调用该函数的地方都直接替换为该函数体中的代码,由此省去了
函数的调用及相应的保存断点、参数传递和返回等操作,从而加快整个程序的执行速度。
【例 5.9】 在给定三角形 3 条边长的情况下使用内联函数 triangleArea 计算三角形面积。
//程序名为 ch05_9.cpp:
#include
inline float triangleArea(float a,float b,float c);
void main( )
{
float sideA,sideB,sideC;
cout<<"Please input the length of the three sides!"<>sideA>>sideB>>sideC;
cout<<"Area of triangle with sides "<
#include
void showLarger(int n1,int n2);
void showLarger(float f1,float f2);
void showLarger(string s1,string s2);
main( )
{
第 5章 函数与预处理
·127·
·127·
int num1=50,num2=100;
float numA=1.1,numB=9.9;
string str1="Sunny day !";
string str2="Wonderful tonight !"
showLarger(nmu1,num2);
showLarger(numA,numB);
showLarger(str1,str2);
}
void showLarger(int n1,int n2)
{
if (n1==n2)
cout<n2)
cout<<"Between "<f2)
cout<<"Between "<s2)
cout<<"Between "<<"\" "s1<<"\""<
void fun(int b)
{
int a=0;
if(b>=a)
{
int c=100;
if(b<=c)
cout <<"b is valid"<
void fun( )
{
for(;;)
{
…
while(1)
{
int b;
cin>>b;
if(b>0)
goto End;
}
}
End:
cout<<"You have been back safely"<
int a;
void main( )
{
a=0;
cout<
int number=1; //全局变量
void addOne(int &num)
{
num++;
}
void main()
{
cout<<"The value of global variable number in outer scope is" < <变量名表>;
例如:auto int x,y; 定义了自动变量 x 与 y,其类型为整型。
有关自动存储类型有以下几点说明。
(1) “auto”可以省略,不写“auto”则隐含确定为自动存储类型。
(2) 自动变量是局部变量,只能定义在函数内,其作用域为块作用域。
(3) 自动变量的生命期属于动态生命期。
(4) 对于自动变量,若没有明确地赋初值时,其初值是不确定的。
2. 寄存器类型(register)
用寄存器类型关键词 register 说明的变量称为寄存器变量,寄存器变量的说明格式为:
register <类型> <变量名表>;
例如:register int a,b; 定义了寄存器变量 a 与 b,其数据类型为整型。
寄存器变量生命期也属于动态生命期,其存储特性与自动变量非常类似,唯一区别是
自动变量存放在内存储器(即内存)中,而寄存器变量存储在 CPU 的寄存器中。由于 CPU 中
寄存器存取速度要比内存储器快得多,所以使用寄存器变量的主要目的是提高程序的运行
速度。常用作循环控制变量。
需要注意的是:对寄存器变量的具体处理方式随不同的计算机系统而有所不同。有的
计算机把寄存器变量作为自动变量来处理,而有的计算机限制了定义寄存器变量的个数等。
3. 外部类型(extern)
用外部类型关键词 extern 说明的全局变量称为外部变量,外部变量的说明格式为:
extern <类型> <变量名表>;
第 5章 函数与预处理
·133·
·133·
例如:extern int a,b; 说明了外部变量 a 与 b,其数据类型为整型。
用 extern 说明外部变量有两个目的,目的之一是在同一文件中使用 extern 说明外部变
量来扩展全局变量的作用域,目的之二是在同一程序的不同文件中使用 exter