首页 理论教育C++函数参数传递技巧解析

C++函数参数传递技巧解析

【摘要】:C++中函数的参数传递有按值传递、地址传递和引用传递。这是因为,该函数的参数是按值传递的,不对实参产生影响。

C++中函数的参数传递有按值传递、地址传递和引用传递。由于地址也是一种值,所以,按值传递和地址传递都是单向的值传递方式。

1.按值传递

所谓按值传递,是指当一个函数被调用时,C++根据实参和形参的对应关系将实际参数值一一传递给形参,供函数执行时使用。函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也不会受到影响。这样的参数,又称为传值参数。

【例1.26】分析以下程序的执行结果。

解:上述程序中,定义了一个函数swap(),它的两个参数都是传值参数,在调用时,直接将实参a的值传递给形参x,实参b的值传递给形参y,但a和b的值不发生变化。程序的执行结果如下:

a=2,b=10

从执行结果看到,swap函数是交换x和y之值,但调用后a和b的值并没有交换。这是因为,该函数的参数是按值传递的,不对实参产生影响。如果想要让形参的改变影响实参,则应选择地址传递或引用传递。

注意:使用指针的参数传递实际上传递的仍然是值,只不过是传递了指针的值。

2.引用传递

(1)什么是引用

引用是一个已知变量的别名,对引用的运算就是对被它关联的变量的运算,也就是说,引用和它所关联的变量享受同等的访问待遇。

(2)建立引用的方法

为建立引用,先写被关联变量的数据类型,后跟引用运算符“&”,再是引用的名字。其一般格式如下:

类型&引用名=已定义的变量名;

例如,以下定义一个变量和它的引用:

double d;

double&rd=d;

这样,rd是double型变量d的引用,也就是说,rd关联了d,以后d和rd均代表内存中同一存储空间的值。

【例1.27】分析以下程序的执行结果。

解:上述程序中,定义了一个整型变量n和它的引用rn,这样rn作为n的别名,两者同步改变。程序的执行结果如下:

n=2,rn=2

n=3,rn=3

n=4,rn=4

(3)引用的特点

引用具有如下特点:

◇引用名字可以是任何合法变量名。

◇引用必须初始化,而且初始化之后还可以成为另外同类型变量的引用。

◇引用的类型和关联变量的类型应该是严格一致的。

◇引用仅在声明时带有“&”,以后就像普通变量一样使用,不能再带“&”。

◇引用的目的在于可以用较清晰的方法编写改变其参数值的函数,以及接受结构体变量和对象作为参数的函数。

(4)引用作为函数参数

在前面介绍的按值传递参数时,将建立参数值的副本,并将其传递给被调用的函数,修改副本并不会影响调用者中原来变量的值(即实参的值)。为了将形参的值回传给实参,可以采用引用传递方式。

引用传递方式是将形参定义成对应实参的引用,即形参作为对应实参的别名,语法上只需在函数声明或定义中形参的数据型后面加上符号“&”即可,其他语法与按值传递相同。

【例1.28】分析以下程序的执行结果。(www.chuimin.cn)

解:上述程序中,函数fun有两个引用型形参max1和min1,用于将形参返回给实参。对于非引用型形参,在调用函数时,是要为形参分配存储空间的,也就是说,形参和对应的实参的存储空间是不同的。而在这里,由于采用引用传递,执行main函数时,给实参max和min分配存储空间,在调用fun函数时,对应的形参max1和min1并不叧外分配存储空间,而共享实参max和min的存储空间,所以max1和min1的值也就是max和min的值。程序的执行结果如下:

Max:9

Min:0

正是由于采用引用传递时,实参和对应的引用型形参共享存储空间,所以当函数调用时传递的数据较大时,为了避免内存开销,可以采用引用传递方式。

(5)引用返回值

所谓引用返回值是指一个函数声明为返回一个引用。函数声明为返回一个引用类型。引用作为返回值时,必须遵守以下规则:

◇不能返回局部变量的引用。其原因是局部变量会在函数返回后被销毁,因此被返回的引用就成了“无所指”的引用,程序会进入未知状态。

◇不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又可能面临其他情况。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成内存泄漏。

【例1.29】分析以下程序的执行结果。

解:上述程序中,由于fun函数返回的是引用,所以可以作为左值直接进行“+=”运算。程序的执行结果如下:

n=30

并不是所有的函数都可以返回引用。一般地,当返回值不是本函数的局部变量时可以返回一个引用,否则,当函数返回时该引用的变量就会被自动释放,所以对它的任何引用都将是非法的。在通常情况下,引用返回值只用在需要对函数的调用重新赋值的场合,也就是对函数的返回值重新赋值的时候。

3.函数的默认参数值

在C++中,允许在函数的声明或定义时给一个或多个参数指定默认值。这样在调用时,可以不给出参数,而按指定的默认值进行工作。

例如,以下是带默认参数值的函数声明:

void fun(int x,int y=0);

该函数将指定的打印机初始化为指定状态。其中第一个参数x表示打印机号码,第二个参数y表示打印机状态。若调用时没有给定第二个参数,系统会自动将打印机的初始化状态设为0。在调用上述函数时可以用以下几种语句:

函数可以将其全部或部分参数声明为带默认值,但带默认值的参数只能放在参数表的最后。这是因为,系统进行参数匹配时是依照从前往后的顺序,如果中间参数有默认值,它就无法判断哪些参数使用默认值。

例如,以下函数声明不正确:

f(int p1=1,int p2,int p3=3);

f(int p1=1,int p2=2,int p3);

f(int p1,int p=2,int p3);

程序还可以通过重新声明函数使本来不带默认值的参数带上默认值,这是使通用函数特定化的有效方法。但需注意:在一个文件中,函数的某一参数只能在一次声明中指定默认值。

例如,以下声明是合法的:

而以下的函数声明是不允许的:

【例1.30】分析以下程序的执行结果。

解:上述程序中,fun()函数是一个带默认参数值的函数,通过重新声明参数默认值,使其第一个参数的默认值为1,第二个参数的默认值为0。程序的执行结果如下:

x=1,y=0

x=0,y=0

x=1,y=1

归纳起来,在设置函数的默认参数值时要注意以下两点:

(1)当函数既有声明又有定义后,不能再在函数定义中指定默认参数。

(2)当一个函数中有多个默认参数时,则形参分布中默认参数应从右到左逐渐定义。在函数调用时,系统按从左到右的顺序将实参与形参结合,当实参的数目不足时,系统将按同样的顺序用声明中或定义中的默认值来补齐所缺少的参数。