4.2 函数的调用
函数定义后,就是为了将来对其进行调用。调用函数是实现函数功能的手段。如何调用函数是C++语言中的一个重要基础内容。C++语言中的函数调用比C语言更加丰富,C++不仅有传值调用(包括传变量地址值的传址调用),而且还有C语言中没有的引用调用。此外,C++语言还允许设置形参的默认值等。
4.2.1 函数的值和类型
函数的调用是用一个表达式来表示的,其调用格式如下:
函数名(实参表)
其中,实参表是由0个、1个或多个实际参数组成的,多个参数用逗号分隔,每个参数是一个表达式。实参的个数由形参决定,实参是用来在调用函数时给形参初始化的。因此,要求在函数调用时,实参的个数和类型要与形参的个数和类型一致,即数目相等,类型相同。实参对形参的初始化是按其位置对应进行的,即第一个实参的值赋给第一个形参,第二个实参的值赋给第二个形参,依此类推。
函数调用是一种表达式,而这里的括号可以理解为函数调用运算符。函数调用表达式的值是函数的返回值,其类型是函数类型。通常使用函数调用的返回值来更新某个变量的值。函数的返回值是在被调用函数中,通过返回语句来实现的。返回语句有两种格式:
格式一:
return(表达式);
格式二:
return;
格式一用于带有返回值的被调用函数中,被调用函数返回的值就是返回语句后面的表达式的值。该值被返回到调用函数中作为调用函数的值。
具有表达式的返回语句实现过程如下:
- 先计算出表达式的值。
- 如果表达式的类型与函数的类型不相同,则将表达式的类型自动转换为函数的类型,这种转换是强制性的,可以出现不保值的情况。
- 将计算出的表达式值返回给调用函数作为调用函数的值。该值可以赋给某变量,也可以直接显示输出。
- 将程序执行的控制权由被调用函数转向调用函数,执行调用函数后面的语句。
当使用无表达式的返回语句时,只返回程序执行的控制权。
return语句的使用说明
- 有返回值的return语句时,用它可以返回一个表达式的值,从而实现函数之间的信息传递。
- 无返回值的函数必须用
void
来说明类型。该函数中可以有return语句,也可以无return语句。当一个被调用函数中无return语句时,程序执行到函数体的最后一条语句时,返回调用函数,相当于函数体的右花括号有返回的功能。函数中也可以有多个return,它们大多出现在if语句中。
4.2.2 函数的传值调用
在C++语言中,函数调用方式除了传值调用之外,还有引用调用。由于C++语言中的变量值有两种:变量本身的值和变量地址值。因此,传值调用也分两种方式:一种是传递变量本身的值,称为传值调用;另一种是传递变量地址的值,称为传址调用。
1. 传值调用的实现机制和特点
使用传值调用方式时,调用函数的实参用常量、变量值或表达式值,被调用函数的形参用变量。调用时系统先计算实参表达式的值,再将实参的值按位置对应赋给形参,即对形参进行初始化。因此,传值调用的实现机制是系统将实参复制一个副本给形参。在被调用函数中,形参可以被改变,但这只影响副本中的形参值,而不影响调用函数的实参值。所以,传值调用的特点是形参值的改变不影响实参,参数传递的开销较大。
[例4.3]传值调用:
#include<iostream.h>
void swap1(int x,int y) {
int temp;
temp = x;
x = y;
y = temp;
cout << "x=" << x << "," << "y=" << y << endl;
}
void main() {
int a = 5, b = 9;
swap1(a, b);
cout << "a=" << a << "," << "b=" << b << endl;
}
执行该程序,输出如下结果:
x=9, y=5
a=5, b=9
main调用swap1时,将a, b的值传给了x, y,但a, b的值不再与swap1有关联,所以在main中a, b的值不受swap1中改变的影响。
2. 传址调用的实现机制和特点
传址调用时,调用函数的实参用地址值,被调用函数的形参用指针。调用时系统将实参的地址值赋给对应的形参指针,使形参指针指向实参变量。因此,传址调用的实现机制是让形参的指针直接指向实参。在被调用函数中,可以通过改变形参指针所指向的实参变量值来间接改变实参值。传址调用的特点是可以通过改变形参所指向的变量值来影响实参。这是一种函数之间传递信息的手段。传址调用时只传递地址值,不复制副本,因此参数传递的开销较小。
[例4.4]传址调用:
#include <iostream.h>
void swap2(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
cout << "x=" << *x << "," << "y=" << *y << endl;
}
void main() {
int a = 5, b = 9;
swap2(&a, &b);
cout << "a=" << a << "," << "b=" << b << endl;
}
执行该程序,输出如下结果:
x=9, y=5
a=9, b=5
通过传址调用,实现了对实参值的改变,从而实现函数之间的信息传递。
4.2.3 函数的引用调用
引用调用是C++语言中的一种函数调用方式,C语言中没有这种方式。引用是一种给变量起别名的机制,对引用的操作就是对被引用变量的操作。引用主要用作函数的形参和函数的返回值。
当引用作函数形参时,调用函数的实参用变量名,将实参变量名传递给形参的引用,相当于在被调用函数中使用了实参的别名。在被调用函数中,对引用的改变直接改变实参的变量值。这种调用具有传址调用的改变实参值和减少开销的特点,但比传址调用更方便直接。因此,C++语言中常使用引用作为函数形参在被调用函数中改变调用函数的实参值。
[例4.5]引用调用:
#include <iostream.h>
void swap3(int &x, int &y) {
int temp;
temp = x;
x = y;
y = temp;
cout << "x=" << x << "," << "y=" << y << endl;
}
void main() {
int a = 5, b = 9;
swap3(a, b);
cout << "a=" << a << "," << "b=" << b << endl;
}
执行该程序,输出结果如下:
x=9, y=5
a=9, b=5
该程序中使用了引用调用。引用调用中,实参用变量名,形参用引用,调用时将实参的变量名赋给对应的形参引用。在被调用函数中,改变引用的值就直接改变了对应的实参值。因此,被调用函数中,x和y的交换,相当于在main()中将a和b的值交换。
在C++语言编程中,经常使用的是传值调用和引用调用,较少使用传址调用,因为传址调用要用到指针,而指针用来传递参数容易出错,所以应尽量使用引用调用来避免使用指针。
[例4.6]引用作为函数参数和返回值:
#include <iostream.h>
int &fun(char, int &, int &);
void main() {
int tn = 0, tc = 0;
cout << "Enter characters:";
char ch;
cin >> ch;
while (ch != '#') {
fun(ch, tn, tc)++;
cin >> ch;
}
cout << "Number characters:" << tn << endl;
cout << "Other characters:" << tc << endl;
}
int &fun(char cha, int &n, int &c) {
if (cha >= '0' && cha <= '9')
return n;
else
return c;
}
执行该程序,显示信息如下:
Enter characters:abc 976235mn 51x#
Number characters:8
Other characters:6
程序分析: 该程序中定义了一个函数fun(),它的参数中有引用,它的返回值是引用。由于fun()函数的返回值是一个int型变量的引用,若对该引用进行增1操作,则被引用的变量也被增1。该例中,n是tn的引用,c是tc的引用;引用n增1,则变量tn也增1。同理,引用c增1,则变量tc也增1。可见,引用作函数类型时,返回的不是一个值,而是一个变量的引用。