1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > C++ 函数参数传递:传值 传指针 传引用

C++ 函数参数传递:传值 传指针 传引用

时间:2020-09-07 22:24:01

相关推荐

C++ 函数参数传递:传值 传指针 传引用

PS:首先理解形参 实参概念。形参是在函数定义的括号内定义的专用变量,它们的目的是保存按实参传递给它们的信息,实参被列在函数调用语句的括号内。

int func(int x)//x是形参{return x*x;}int main(void){int a = 3;func(a);//a是实参return 0;}

上面的代码中,x是形参,a是实参。形参x是实参a的一个拷贝

1.C++ 按值传递

采用按值传递的方式,当信息被传递给一个函数时,这意味着形参接收的是传递给它的值的副本。如果形参的值在函数内部被改变,那么它对原始实参是没有影响的。

#include <iostream>using namespace std;// 函数声明void changeMe(int aValue);int main(){int number = 12;// 输出number的值此处输出为 12cout << "In main number is " << number << endl;//调用changeMe()函数,将number中的值作为参数传递changeMe(number); //此处调用函数内部有一个输出为 0// 调用函数之后,再次输出number的值此处输出为 12cout << "Back in main again, number is still " << number << endl;return 0;}void changeMe(int myValue){//改变 myValue 的值为 0myValue = 0;//输出 myValue的值 此处输出为 0cout << "In changeMe, the value has been changed to " << myValue << endl;}

程序输出结果:

In main number is 12

In changeMe, the value has been changed to 0

Back in main again, number is still 12

当函数原型列出变量名称和数据类型时,它使用的名称只是虚拟名称,编译器实际上并不使用它们,并且不必在函数头中使用一致的名称。第 5 行中的 changeMe 函数原型和第 19 行中的 changeMe 函数头都指定该函数具有一个 int 形参,但它们使用了不同的名称。

并且,即使在 changeMe 函数中形参变量 myValue 已更改,实参 number 也不会被修改。这是因为 myValue 变量只包含了 number 变量的副本。只是这个副本被改变,而不是原来的。changeMe 函数无法访问原始实参。图 1 说明了形参变量在内存中的存储位置与原始实参的存储位置是分开的。

2.C++ 指针传递

传指针就是把实参的地址传递给函数。传指针可以修改实参的值,在C++里也不会存在调用对象的拷贝构造函数的问题, 传指针的效率比传值要高。所以,如果需要修改实参的值,就不能传值,而需要传指针等。但是,传指针比传值复杂,指针计算一旦移动出了正常范围,会造成程序的非法访问等。

void func(int *x)//func采用了传指针的形式{*x = *x+1;printf("*x=%d\n", *x);}int main(void){int a = 0;func(&a);//把实参a的地址传递给了函数funcprintf("a=%d\n", a);return 0;}

分析:传指针可以修改实参的值。根据指针的定义,*x就是a,所以,*x=*x+1,即为a = a+1,所以上面的代码输出结果为:

*x=1

a=1

C/C++ 禁止在函数调用时直接传递数组的内容,而是强制传递数组指针

而对于结构体和对象没有这种限制,调用函数时既可以传递指针,也可以直接传递内容;为了提高效率,我曾建议传递指针,这样做在大部分情况下并没有什么不妥,读者可以点击《C语言结构体指针》进行回顾。

在 C++ 中,我们有了一种比指针更加便捷的传递聚合类型数据的方式,那就是引用(Reference)

3.C++ 引用传递

引用介绍参照博客/m0_37957160/article/details/104705220

前面讲过,实参通常是通过值传递给函数的,这意味着形参接收的只是发送给它们的值的副本,它们存储在函数的本地内存中。对形参值进行的任何更改都不会影响原始实参的值。然而,有时候可能会希望一个函数能够改变正在调用中的函数(即调用它的函数)中的一个值,这可以通过引用传递的方式来完成。

我们知道,变量是可以保存数据的内存位置的名称。当使用变量时,实际上就是访问存储在分配给它的内存位置的数据。引用变量是变量的另一个别名,它没有自己的存储数据的内存位置,它访问的是另一个变量的内存位置。对引用变量作出的任何更改,实际上都是对它所引用的变量内存位置中存储数据的更改。

当使用引用变量作为形参时,它将变为实参列表中相应变量的别名,对形参进行的任何更改都将真正更改正在调用它的函数中的变量。当以这种方式将数据传递给形参时,该实参被称为按引用传递。

在定义或声明函数时,我们可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一份数据。如此一来,如果在函数体中修改了形参的数据,那么实参的数据也会被修改,从而拥有“在函数内部影响函数外部数据”的效果。

引用变量的定义方法和常规变量类似,但是其数据类型和名称之间有一个&符号。例如,以下函数定义使形参 refVar 成为引用变量:

void doubleNum(int& refVar){refVar *= 2;}

注意,变量 refVar 被称为“对 int 的引用”。

该函数将 refVar 乘以 2,因为 refVar 是引用变量,所以该操作实际上将对作为实参传递给函数的变量执行。

具有引用形参的函数的原型也必须具有&符号。与函数头一样,它在数据类型和变量名之间。如果原型中省略了变量名,那么&符号将跟在数据类型后面。以下所有 doubleNum 函数的原型都是正确的:

void doubleNum(int &refVar);void doubleNum(int& refVar);void doubleNum(int &);void doubleNum(int&);

注意,&符号必须出现在使用引用变量作为形参的任何函数的原型和函数头中。它不会出现在函数调用中。

#include <iostream>using namespace std;// Function prototype. The parameter is a reference variable.void doubleNum(int SrefVar);int main(){int value = 4;cout << "In main, value is " << value << endl;//输出4cout << "Now calling doubleNum..." << endl;doubleNum(value); cout << "Now back in main, value is "<< value << endl; //输出4return 0;}void doubleNum (int SrefVar){refVar *= 2;}

程序输出结果:

In main, value is 4

Now calling doubleNum...

Now back in main, value is 8

此程序中的形参 refVar “指向”函数 main 中的 value 变量。当程序使用一个引用变量时,它实际上是使用它所引用或指向的变量,(引用变量实际上指向的是被它引用的变量)

当函数的目的是接收调用它的函数存储在变量中的输入值时,使用引用变量作为函数 形参特别有用。另外,引用形参还可以用于必须从函数发回多个值的情形。如果函数将计算并发回单个值,通常认为使用返回值的函数更合适,可以使用 return 语句返回值。

下面程序是对之前程序的修改。它添加了一个函数 getNum,该函数接收用户的输入并将其存储在 userNum 中,但是,形参 userNum 是对 main 的变量 value 的引用,所以这是实际存储输入数据的位置。

#include <iostream>using namespace std;//Function prototypesvoid getNum(int &);int doubleNum(int);int main(){int value;// Call getNum to get a number and store it in valuegetNum(value);value = doubleNum(value); //调用函数后,将value变为24// Display the resulting numbercout << "That value doubled is " << value << endl;//最后输出 24return 0;}void getNum(int &userNum){cout << "Enter a number: ";cin >> userNum; //输入12}int doubleNum (int number){return number *2;}

程序输出结果:

Enter a number: 12

That value doubled is 24

注意,只有变量才能按引用传递。如果尝试将非变量实参(例如常数、常量或表达式)传递到引用形参中,将导致错误。

如果一个函数有多个形参是引用变量,则必须在原型和函数头中为每个形参使用&符号。以下是使用 4 个引用变量形参的函数的原型:

void addThree(int& num1, int& num2, int& num3, int& sum);

以下是函数定义:

void addThree(int& numl, int& num2, int& num3, int& sum){cout << "Enter three integer values: ";cin >> num1 >> num2 >> num3;sum = num1 + num2 + num3;}

但是请注意,addThree 函数只需要一个引用形参 sum,其他 3 个形参可以通过值接收它们的实参,因为在此处的函数中没有改变它们。

提示:应该仅在绝对需要时才使用引用变量。任何时候允许一个函数来改变函数之外的变量,其实都是在创建潜在的调试问题。

文章转自C语言中文网:/view/2251.html

引用的本质:

在定义或声明函数时,我们可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一份数据。如此一来,如果在函数体中修改了形参的数据,那么实参的数据也会被修改,从而拥有“在函数内部影响函数外部数据”的效果。

总之:传值不能修改实参,且如果是对象,效率较低;传指针能够修改实参,效率较高,但容易出错;传引用能够修改实参,效率较高,而且不易出错。

一个能够展现按引用传参的优势的例子就是交换两个数的值,如下所示:

#include <iostream>using namespace std;void swap1(int a, int b);void swap2(int *p1, int *p2);void swap3(int &r1, int &r2);int main() {int num1, num2;cout << "Input two integers: ";cin >> num1 >> num2;swap1(num1, num2);cout << num1 << " " << num2 << endl; //输出与输入相同,因为值传递,不能改变原始数据cout << "Input two integers: ";cin >> num1 >> num2;swap2(&num1, &num2);cout << num1 << " " << num2 << endl; //输出与输入相反,指针传递可以改变原始数据cout << "Input two integers: ";cin >> num1 >> num2;swap3(num1, num2);cout << num1 << " " << num2 << endl;//输出与输入相反,因为引用传递,可以改变原始数据return 0;}//直接传递参数内容void swap1(int a, int b) {int temp = a;a = b;b = temp;}//传递指针void swap2(int *p1, int *p2) {int temp = *p1;*p1 = *p2;*p2 = temp;}//按引用传参void swap3(int &r1, int &r2) {int temp = r1;r1 = r2;r2 = temp;}

运行结果:

Input two integers: 12 34↙

12 34

Input two integers: 88 99↙

99 88

Input two integers: 100 200↙

200 100

本例演示了三种交换变量的值的方法:

1) swap1() 直接传递参数的内容,不能达到交换两个数的值的目的。对于 swap1() 来说,a、b 是形参,是作用范围仅限于函数内部的局部变量,它们有自己独立的内存,和 num1、num2 指代的数据不一样。调用函数时分别将 num1、num2 的值传递给 a、b,此后 num1、num2 和 a、b 再无任何关系,在 swap1() 内部修改 a、b 的值不会影响函数外部的 num1、num2,更不会改变 num1、num2 的值。

2) swap2() 传递的是指针,能够达到交换两个数的值的目的。调用函数时,分别将 num1、num2 的指针传递给 p1、p2,此后 p1、p2 指向 a、b 所代表的数据,在函数内部可以通过指针间接地修改 a、b 的值。我们在《C语言指针变量作为函数参数》中也对比过第 1)、2) 中方式的区别。

2) swap3() 是按引用传递,能够达到交换两个数的值的目的。调用函数时,分别将 r1、r2 绑定到 num1、num2 所指代的数据,此后 r1 和 num1、r2 和 num2 就都代表同一份数据了,通过 r1 修改数据后会影响 num1,通过 r2 修改数据后也会影响 num2。

从以上代码的编写中可以发现,按引用传参在使用形式上比指针更加直观。在以后的 C++ 编程中,我鼓励读者大量使用引用,它一般可以代替指针(当然指针在C++中也不可或缺),C++ 标准库也是这样做的。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。