文章目录
函数
1 函数的定义与使用
1.1 函数的定义
我想设计一个程序完成下面的计算,该如何设计程序最有效?
函数定义的一般形式为:
返回类型 函数名(形式参数列表)
{
函数体声明部分
函数体执行语句
}
(1)函数名
实现函数需要确定函数名,以便使用函数时能够按名引用。
(2)形式参数列表
形式参数列表是函数与调用者进行数据交换的途径,一般形式为:
函数可以没有形式参数,定义形式为:
(3)返回类型
返回类型可以是C++除数组之外的内置数据类型或自定义类型。
函数可以不返回数据,此时返回类型应写成void
,表示没有返回值,其形式为:
没有返回值的函数,在调用处是不能按表达式来调用函数的,只能按语句形式调用函数,因为函数没有返回值也就不能参与表达式运算。
m=max(a,b); //以表达式的方式调用max函数
print( ); //以语句的形式调用print函数
当函数的返回类型不是void
,表明函数有返回值。如果函数体内没有return
语句,此时函数返回的值是与返回类型相同但内容却是随机的一个值。
(4)函数体
实现函数最重要的是编写函数体。函数体(function body)包含声明部分和执行语句,是一组能实现特定功能的语句序列的集合。
- 编写函数体是为了实现函数功能。故称函数定义为函数实现,简称实现。
- 而函数头简称(函数的第一行)接口。
例子:使用函数实现判断一个数是否是素数。
# include<iostream> // 标准输入输出函数库
using namespace std;
int IsPrime(int m) // 求素数函数
{
// 枚举法求m是否为素数
int i;
for (i = 2; i < m - 1; i++)
{
if (m % i == 0)return 0; // 不是素数返回0
return 1; // 是素数返回1
}
}
int main()
{
int m;
cin >> m;
if (IsPrime(m)) cout << "Yes" << endl; //是素数输出Yes
else cout << "No" << endl; // 不是素数输出No
return 0;
}
1.2 函数的参数
函数参数是实现函数时的重要内容,是函数接口的首要任务,围绕这个目标需要研究:
形式参数的定义与实际参数的对应关系。
函数参数的数据传递机制,包括主调函数与被调函数的双向数据传递。
形式参数
函数定义中的形式参数列表(parameters),简称形参。例如:
第1行a
和b
就是形参。
形式参数相关说明:
1)函数定义时指定的形参,在未进行函数调用前,并不实际占用内存中的存储单元。
2)只有在发生函数调用时,形参才分配实际的内存单元,接受从主调函数传来的数据。
3)当函数调用结束后,形参占用的内存单元被自动释放
实际参数
函数调用时提供给被调函数的参数称为实际参数(arguments),简称实参。
实参必须有确定的值,因为调用函数会将它们传递给形参。实参可以是常量、变量或表达式,还可以是函数的返回值。例如:
实参相关说明:
1)实参的类型、次序和数目要与形参一致。
2)如果参数数目不一致,则出现编译错误;
3)如果参数次序不一致,则传递到被调函数中的数据就不合逻辑,难有正确的程序结果;
4)如果参数类型不一致时,则函数调用时按形参类型隐式类型转换实参;
程序通常有两种函数参数传递机制——值传递和引用传递。
值传递(pass-by-value)过程中,形参作为被调函数的内部变量来处理,即开辟内存空间以存放由主调函数复制过来的实参的值,从而成为实参的一个副本。
值传递的特点是被调函数对形参的任何操作都是对内部变量进行,不会影响到主调函数的实参变量的值
值传递时,实参数据传递给形参是单向传递,即只能由实参传递给形参,而不能由形参传回给实参。
1.3 函数的声明
当要调用函数时,C++语言规定在调用一个函数之前必须有该函数的声明。
C++规定函数的定义既是函数定义,也是函数声明。换言之,只要函数调用是写在函数定义的后面,就自然有了函数声明。
声明的作用是程序向编译器提供函数的接口信息,因而多次提供接口信息是允许的,但不能提供相互矛盾、语义不一致的接口信息。
函数原型
函数原型(function prototype)的作用是提供函数调用所必须的接口信息,使编译器能够检查函数调用中可能存在的问题,有两种形式:
- 第一种形式:
- 第二种形式:
# include<iostream> // 标准输入输出函数库
using namespace std;
int gcd(int m, int n); // gcd函数原型,gcd函数声明在前
int main()
{
int m, n;
cin >> m >> n;
cout << gcd(m, n) << endl; // 调用时已有gcd函数声明
return 0;
}
int gcd(int m, int n) //求最大公约数,gcd函数实现在main后
{
int r;
while (n != 0)
{
r = m % n;
m = n;
n = r;
}
return m;
}
函数调用
有了函数声明,就可以调用函数,有参数函数调用的形式为:
函数名(实参列表)
实参可以是常量、变量、表达式和函数调用,各实参之间用逗号(,)
分隔。实参的类型、次序、个数应与形参一致。
在C++语言中,可以用以下几种方式调用函数。
1.4 内联函数
C++提供一种提高函数效率的方法,即在编译时将被调函数的代码直接嵌入到主调函数中,取消调用这个环节。这种嵌入到主调函数中的函数称为内联函数(inline function)。
内联函数的声明是在函数定义的类型前加上inline
修饰符,定义形式为:
内联函数中不允许用循环语句和switch
语句(复杂的语句)。(有点像中断
)
内联函数的声明必须出现在内联函数第一次被调用之前。
例子:
# include<iostream> // 标准输入输出函数库
using namespace std;
inline int fun(int a, int b)
{
return a * a + b * b;
}
int main()
{
int n = 5, m = 8, k;
k = fun(n, m); // 调用点嵌入a*a+b*b
cout << "k=" << k << endl;
return 0;
}
实线为一般函数;虚线为内联函数。
2 默认参数与函数重载
2.1 默认参数
C++允许在函数定义或函数声明时,为形参指定默认值,这样的参 数称为默认参数(default argument),一般形式为:
(1)如果在函数定义时设置了默认参数,那么就不能在函数声明 中再次设置,反之亦然。
(2)可以设置多个默认参数,设置的顺序为自右向左,换言之, 要为某个参数设置默认值,则它右边的所有参数必须都是默认参数。
(3)默认值可以是常量、全局变量,甚至是一个函数调用(调用 实参必须是常量或全局变量的表达式),不可以是局部变量。
默认参数函数的调用
默认参数本质上是编译器根据函数声明或函数定义时的默认参数设 置,对函数调用中没有给出来的实参自动用默认值表达式“补齐” 再进行编译。
2.2 函数重载
函数重载(function overloading)是在同一个域中用同一个函数名来定义多个函数,但函数参数列表应彼此有不同,或者是参数个数不同,或者是参数类型不同,或者两者均有不同。
函数重载的使用说明:
(1)重载函数的形参必须不同(个数不同或类型不同)。
(2)编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
(3)不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。
3 函数模板
函数模板(function template)是一个独立于类型的函数,可作为一种模式,产生函数的特定类型版本。
函数模板能建立一个通用功能的函数,以支持多种不同形参,进一步简化了重载函数的设计。
重载的情况(函数体要描写两次):
使用函数模板可以设计通用型的函数,这些函数与类型无关并且只 在需要时自动实例化,从而形成“批量型”的编程方式。
函数模板定义的语法形式为:
用
T
T
T代表一种不确定的数据类型,然后在描述函数时用
T
T
T代替相应的数据类型
模板形参表(template parameter list)是用一对尖括号括< >
括起 来的一个或多个模板形参的列表,不允许为空,形参之间以逗号分 隔,其形式有两种。
- 第一种形式
如上文例子。
- 第二种形式
4 库函数的调用
所谓库函数是指事先由程序员编制好的函数。
多数情况下,基于各种理由,如保护知识产权,这些库函数仅提供二进制形式的目标代码给调用者链接,却没有提供源码形式的函数定义。
(1)在程序中添加库函数声明
多数库函数将自己的函数原型和特殊数据等放在头文件(.h
)中, 所以应首先使用文件包含命令将这些头文件包含到程序中。例如欲 使用数学库函数,文件包含命令为:
#include <cmath>
从而使得程序有函数声明,例如:
y=sin(x);
调用就能够通过编译
(2)将库函数目标代码连接到程序中。
在连接时,例如使用了sin
函数,就必须要有sin
函数的实现代码才 能生成可执行文件,否则连接出错。要将库函数的目标代码能够连接到程序中,主要是配置好开发环境的相关参数,然后由连接器处理。
标准库函数的连接在开发环境中是默认的,一般可以不用特别设置。
5 函数的嵌套调用
在调用一个函数的过程中,又调用另一个函数,称为函数的嵌套调用,C++允许函数多层嵌套调用,只要在函数调用前有函数声明即可。
6 函数的递归调用
古之欲明明德于天下者,先治其国;欲治其国者,先齐其家;欲齐其家者,先修其身;欲修其身者,先正其心;欲正其心者,先诚其意;欲诚其意者,先致其知,致知在格物。
物格而后知至,知至而后意诚,意诚而后心正,心正而后身修,身修而后家齐,家齐而后国治,国治而后天下平。
函数直接或间接调用自己称为递归调用。C++语言允许函数递归调用,如图(a)所示为直接递归调用,如图(b)所示为间接递归调 用。
C++程序设计-西北工业大学-魏英、姜学锋、刘君瑞