我们都知道,在函数定义括号中的参数是形参,是给函数内专用的局部变量,意味着函数接收到的是实参的副本,如果形参的值在函数内部被改变,对实参是没有影响的。
#include <iostream> using namespace std; void change(int formalNum) { formalNum = 0; cout << "formalNum address: " << &formalNum << endl; } int main() { int realNum = 10; cout << "Before Change: " << realNum << endl; cout << "realNum address: " << &realNum << endl; change(realNum); cout << "After Change: " << realNum ; return 0; } // 执行结果 Before Change: 10 realNum address: 008FFDA0 formalNum address: 008FFCCC After Change: 10
可以看见,实参和形参的地址完全不一样,而且函数完全没有办法改变实参的值。值传递的作用更多是让函数内部了解外部参数的值。值传递是单向的,只能由实参传向形参。
指针传递很好理解,形参为指向实参地址的指针,当对形参操作时,等同于直接通过地址操作实参。
#include <iostream> using namespace std; void change(int *ptr) { *ptr = 0; } int main() { int realNum = 10; int* ptr = &realNum; cout << "Before Change: " << realNum << endl; change(ptr); cout << "After Change: " << realNum ; return 0; } // 执行结果 Before Change: 10 After Change: 0
引用传递其实是最难理解的一种传参方式。在详细剖析它之前,我们先说他的功能。
向函数传递参数的引用调用方法,把引用的地址复制给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
那么肯定有人问了,既然都是直接影响,指针和引用有啥区别呢???那区别可大了去了。
引用的规则:
看了这么多,指针传递和引用传递的用处是什么呢?
下面看具体操作:
引用变量的定义方法和常规变量类似,但是其数据类型和名称之间有一个 & 符号。例如,以下函数定义使形参 refNum 成为引用变量:
#include <iostream> using namespace std; void change(int& refNum) { refNum = 0; cout << "reference address: " << &refNum << endl; } int main() { int realNum = 10; cout << "Before Change: " << realNum << endl; cout << "realNum address: " << &realNum << endl; change(realNum); cout << "After Change: " << realNum ; return 0; } // 执行结果 Before Change: 10 realNum address: 00A4F9F4 reference address: 00A4F9F4 After Change: 0
可以看见,引用传递成功地改变了参数的值,同时形参的地址和实参的地址其实是一模一样的。
在学完数据结构和算法后,我对其又有新的认识。
void func(nodeList* &Node){ // 这里对Node进行了操作 }
上面这个传参,又有*又有&,第一眼有点懵,后来细想一下其实很简单。
nodeList是一个整体,代表传进来的是nodeList这个类的指针。我们之前已经学到了,指针其实是一个变量,它的基本性质和变量没有区别。那么我们要在函数体内改变其值,最安全的办法就是传入其引用(也可以创建指针的指针)。所以这里的&Node表示引用Node的实参,是Node的别名,操作引用变量就相当于操作实参变量。*