#代码示例
##值传递
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
##指针传递
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
##引用传递
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
话不多说,先上代码,在代码中看区别
#include<iostream>
using namespace std;
//值传递
void zhiChuandi(int n) {
cout << "值传递--函数操作地址" << &n << endl; //显示的是拷贝的地址而不是源地址
n++;
}
//引用传递
void YinyongChuandi(int & n) {
cout << "引用传递--函数操作地址" << &n << endl;
n++;
}
//指针传递
void ZhizhenChuandi(int *n) {
cout << "指针传递--函数操作地址 " << n << endl;
*n += 1;
}
int main() {
int n = 10;
cout << "实参n的地址" << &n << endl;
zhiChuandi(n);
cout << "after zhiChuandi() n=" << n << endl;
YinyongChuandi(n);
cout << "after YinyongChuandi() n=" << n << endl;
ZhizhenChuandi(&n);
cout << "after ZhizhenChuandi() n=" << n << endl;
system("pause");
return true;
}
运行结果如图 值传递和引用传递虽然在调用时都写的是“n”,即zhiChuandi(n)和YinyongChuandi(2)但其背后实际操作截然不同,值传递很好理解,相当于做了一个copy,在不影响原变量值的情况下,仅对copy好的新变量进行操作。但引用传递,或者理解成“址传递”,虽然也写成YinyongChuandi(n),但他实际上根据YinyongChuandi(int &n)这个函数定义,把拿到的参数n的内存地址给搞到了,然后后续在函数体中虽然也一直写n怎么怎么样,但这个操作其实已经是对原参数(而非新的copy)的操作了。指针传递是另外一种形式的“址传递”,他和“引用传递”的区别在于:如果认为引用传递稍微“智能”一些,即只需在函数定义的形参上加一个&表示要取的是地址就行,指针传递则更加“低级粗暴”,直接在函数定义时指明形参要的就是地址值,要求把地址传递进来。所以在写ZhizhenChuandi(&n)时,就不和YinyongChuandi(n)这般这么智能方便,而是必须手工写上取地址符&,从而把地址传进来。另外,在函数体内的使用中,明显发现引用传递要简单一些,变量该怎么写还是怎么写,相当于忽略该独立出来的函数,直接操作原数。而指针传递就得不断的加去内容符 ,比如n=*n+1,这是因为传递进来的n本身是个地址,不得不加 * 去该地址取内容
#引用传递和指针传递的区别
##引用的规则:
- 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)
- 不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)
- 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)
##指针传递的实质: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)。 指针传递和引用传递一般适用于: 函数内部修改参数并且希望改动影响调用者。对比指针/引用传递可以将改变由形参“传给”实参(实际上就是直接在实参的内存上修改, 不像值传递将实参的值拷贝到另外的内存地址中才修改)。另外一种用法是:当一个函数实际需要返回多个值,而只能显式返回一个值时,可以将另外需要返回的变量以指针/引用传递给函数,这样在函数内部修改并且返回后,调用者可以拿到被修改过后的变量,也相当于一个隐式的返回值传递吧。 ##概念上的区别 从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变) 而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。 引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。 为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别: 程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。