引言:
从概念上讲:
指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。
引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。
指针和引用的区别:
- 引用不可以为空,但指针可以为空。故定义一个引用的时候,必须初始化。
- 引用不可以改变指向,对一个对象"至死不渝";但是指针可以改变指向,而指向其它对象。说明:虽然引用不可以改变指向,但是可以改变初始化对象的内容。例如就++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。
- 引用的大小是所指向的变量的大小,因为引用只是一个别名而已;指针是指针本身的大小,4个字节。
- 引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为NULL,所以不安全。const 指针虽然不能改变指向,但仍然存在空指针,并且有可能产生野指针(即多个指针指向一块内存,free掉一个指针之后,别的指针就成了野指针)。
总之:指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。
1、值传递
形参是实参的拷贝,改变形参的值并不会改变外部实参的值。只有当调用函数调用被调函数时,编译器才会为其中的形参m和n以及变量temp分配内存区域,并用实参x和y对形参m和n赋值,swap1函数中进行的数值交换是对m和n进行的操作,并不会影响main函数中的x和y,而且m、n和temp在swap1函数执行完毕后便会被撤销,所占内存区域被收回。
换句话说,被调函数中执行的任何操作都只作用于被调函数内的变量上,而不作用于调用函数的变量上,通过值传递,被调函数无法改变调用函数中的变量值。
2、指针传递
形参为指向实参地址的指针,当对形参的指向操作时,将相当于对实参本身进行操作。
3、引用传递
形参相当于实参的“别名”,对形参的操作实际上就是对实参的操作,在引用传递过程中,被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是调用函数放进来的实参变量的地址。
如:
#include<iostream> #include<stdlib.h> using namespace std; int main() { void swap1(int m,int n); void swap2(int *m,int *n); void swap3(int &m,int &n); int x=5,y=8; cout<<"x与y交换前:x="<<x<<",y="<<y<<endl; cout<<"变量x的地址是:"<<&x<<" 变量y的地址是:"<<&y<<endl; cout<<endl; swap1(x,y); cout<<"x与y按值传递,交换后:x="<<x<<",y="<<y<<endl; cout<<endl; swap2(&x,&y); cout<<"x与y按指针传递,交换后:x="<<x<<",y="<<y<<endl; cout<<endl; swap3(x,y); cout<<"x与y按引用传递,交换后:x="<<x<<",y="<<y<<endl; cout<<endl; system("pause"); return 0; } //值传递 void swap1(int m,int n) { int temp; temp=m; m=n; n=temp; cout<<"形参m的地址是:"<<&m<<" 形参n的地址是:"<<&n<<endl; } //指针传递 void swap2(int *m,int *n) { int temp; temp=*m; *m=*n; *n=temp; cout<<"形参m的地址是:"<<&m<<" 形参n的地址是:"<<&n<<endl; } //引用传递 void swap3(int &m,int &n) { int temp; temp=m; m=n; n=temp; cout<<"形参m的地址是:"<<&m<<" 形参n的地址是:"<<&n<<endl; }
小结:
- 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
- 引用传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
注意:引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。