ITEEDU

5.4 按引用调用函数

C++用三种方式向函数传递数值:按值调用(call-by-value)、用引用参数按引用调用(call-by-reference reference argument)和用指针参数按引用调用(call-by-reference pointer argument)。第3章比较了按引用调用与按值调用,本章主要介绍用指针参数按引用调用。

第3章曾介绍过,return可以从被调用函数向调用者返回一个值(或不返回值而从被调用函数返回控制)。我们还介绍了用引用参数将参数传递给函数,使函数可以修改参数的原有值(这样可以从函数“返回”多个值),或将大的数据对象传递给函数而避免按值调用传递对象的开销(即复制对象所需的开销)。指针和引用一样,也可以修改调用者的一个或几个变量,或将大的数据对象指针传递给函数而避免按值调用传递对象的开销。

在C++中,程序员可以用指针和间接运算符模拟按引用调用(就像C语言程序中的按引用调用一样)。调用函数并要修改参数时,传递该参数地址,通常在要修改数值的变量名前面加上地址运算符( &)。第4章曾介绍过,数组不能用地址运算符(&)传递,因为数组名是内存中数组的开始位置(数组名等同于&arrayName[0]),即数组名已经是个指针。向函数传递参数地址时,可以在函数中使用间接运算符形成变量名的同义词、别名或浑名,并可用其修改调用者内存中该地址的值(如果变量不用const声明)。

图5.6和5.7的程序是计算整数立方函数的两个版本cubeByValue和cubeByReference。图5.6按值调用将变量number传递给函数cubeByValue。函数cubeByValue求出参数的立方,并将新值用return语句返回main,井在main中将新值赋给number。可以先检查函数调用的结果再修改变量值。例如,在这个程序中,可以将cubeByValue的结果存放在另一变量中,检查其数值,然后再将新值赋给number。

  // Fig. 5,6: fig0506,cpp
 // Cube a variable using call-by-value
 #include < iostream.h>
 int cubeByValue( int );  // prototype
 int main()
 {
   int number = 5;
   cout << "The original value of number is "<< number;
   number = cubeByValue( number );
   cout << "\nThe new value of number is" << number << endl;
   return 0;
 }
 int cubeByValue( int n )
   {
   return n * n * n;  // cube local variable n
} 

输出结果:

The original value of number is 5

The new value of number is 125

图5.6 按值调用求出参数的立方

图5.7的程序按引用调用传递变量nunber(传递number的地址)到函数cubeByReference。函

数cubeByReference取nPtr(int的指针)作为参数。函数复引用指针并求出nPtr所指值的立方,从

而改变main中的number值。图5.8和5.9分别分析了图5.6和1.7所示程序。
// Fig. 5.7: fig05_07.cpp
 // Cube a variable using call-by-reference
 // with a pointer argument
 #include < iostream.h>
 void cubeByReference( int* );  // prototype
 int main()
 {
   int number = 5;
   cout << "The original value of number is "<< number;
   cubeByReference( &number );
   cout << "\nThe new value of number is "<< number << endl;
   return O;
 }
 void cubeByReference( int *nPtr )
 {               
   *nPtr = *nPtr = *nptr * *nptr;  // cube number in main
 }

输出结果:

The original value of number is 5

The new value of number is 125

图 5.7 用指针参数按引用调用求出参数的立方

常见编程错误5.5

要复引用指针以取得指针所指的值时不复引用指针是个错误。

接收地址参数的函数要定义接收地址的指针参数。例如,cubeByReference的函数首部如下所示:

void   cubeByReference(int   *nPtr)  

这个函数首部指定函数cubeByReferenee接收整型变量的地址(即整型指针)作为参数,在nPtr中局部存放地址,不返回值。

cubeByReference的函数原型包含括号中的int*。和其他变量类型一样,不需要在函数原型中包括指针名。参数名仅用于程序中的说明,编译器将

其忽略。

在需要单下标数组参数的函数首部和函数原型中,可以用cubeByReference参数表中的指针符号。编译器并不区分接收指针的函数和接收单下标数组的函数。当然,函数必须“知道”何时接收数组或要进行按引用调用的单个变量。编译器遇到形如int b[]的单下标数组函数参数时,编译器将参数变为指针符号int* const b(b是指向整数的常量指针),const见第51节介绍。声明函数参数为单下标数组的两种形式可以互换。

编程技巧5.2
除非调用者显式要求被调用函数修改调用者环境中参数变量的值,否则按值调用将参数传递给函数。这是最低权限原则的另一个例子。

图5.8典型的按值调用分析


图 5.9典型的用指针参数按引用调用分析