在介绍指针/引用参数之前,先来介绍函数的传递方式。在C++中,函数参数主要采用两种传递方式:值传递和引用传递。所谓值传递是指在调用函数时将实际参数复制一份传递到函数中,这样,在函数中如果对参数进行修改,将不会影响到实际参数;而引用传递是指在调用函数时将实际参数的地址传递到函数中,那么,在函数中对参数所进行的修改,将影响到实际参数。
下面编写一个按值传递的函数OutputNumber,函数的作用是输出一个数值。
例4.2
- void
OutputNumber(int nNumber) - {
-
cout << nNumber << endl; //输出数值 -
nNumber = 20; //修改参数 - }
在main函数中调用OutputNumber函数。
- int
main(int argc, char* argv[]) - {
-
int nNum = 10; //定义一个变量 -
OutputNumber(nNum); //调用OutputNumber函数 -
cout << nNum << endl; //输出变量值 -
return 0; - }
运行程序,效果如图4.4所示。
从图4.4中可以发现,在OutputNumber函数中输出的数值是10,尽管在该函数中将参数nNumber设置为20,但是在main函数中执行"cout << nNum << endl;"语句时,输出的结果仍为10。因为OutputNumber函数采用按值传递,对形式参数nNumber的修改不会影响到实际参数nNum。
如果修改OutputNumber函数,将参数的类型修改为引用类型,则OutputNumber函数将按引用方式传递。
![]() |
图4.4 |
例4.3
- void
OutputNumber(int &nNumber) //设置引用类型参数 - {
-
cout << nNumber << endl; //输出结果 -
nNumber = 20; //修改参数值,将影响到实际参数 - }
- int
main(int argc, char* argv[]) - {
-
int nNum = 10; //定义一个变量 -
OutputNumber(nNum); //调用OutputNumber函数 -
cout << nNum << endl; //输出变量值 -
return 0; - }
运行程序,效果如图4.5所示。
![]() |
图4.5 |
从图4.5中可以发现,在OutputNumber函数中将形式参数nNumber设置为20,实际参数nNum的值也为20。因为引用传递,传递的是参数的地址,对nNumber的修改自然会影响到nNum。
许多读者可能会问,如何判断函数是值传递还是引用传递呢?这需要根据参数的数据类型来判断,如果参数的数据类型是指针类型、引用类型或数组类型,则函数是引用传递,其他情况下是值传递。因此,不仅只有引用数据类型才是按引用传递,指针和数组类型参数同样是按引用传递。下面修改函数OutputNumber,采用指针作为函数参数。
例4.4
- void
OutputNumber(int *pNumber) //使用指针作为函数参数 - {
-
cout << *pNumber << endl; //输出参数值 -
*pNumber = 20; //设置参数值 - }
- int
main(int argc, char* argv[]) - {
-
int nNum = 10; //定义一个整型变量 -
OutputNumber(&nNum); //调用OutputNumber函数 -
cout << nNum << endl; //输出nNum -
return 0; - }
运行程序,效果与图4.5是相同的。
在编写函数时,如果函数需要采用引用方式传递,使用指针和引用作为参数类型都是可以的。使用指针和引用类型作为函数参数各有优缺点,视具体环境而定。对于引用类型,引用必须被初始化为一个对象,并且不能使它再指向其他对象,因为对引用赋值实际上是对目标对象赋值。这是引用类型的缺点,但也是引用类型的优点,因为在函数调用时需要验证引用参数的合法性。例如,如果函数OutputNumber采用引用参数类型,则语句"OutputNumber(0);"是非法的。如果函数OutputNumber采用指针类型参数,则语句"OutputNumber(0);"是合法的。因为0被认为是一个空指针,对空指针操作必然会导致地址访问错误。因此对于指针对象作为函数参数,函数体中需要验证指针参数是否为空。这是使用指针类型作为函数参数的缺点。但是,使用指针对象作为函数参数,用户可以随意修改指针参数指向的对象,这是引用类型参数所不能的。