前言
从概念上讲,指针从本质上讲就是存储变量地址的一个变量,在逻辑上是独立的,可以被改变,包括其指向的地址的改变和其指向的地址中所存放的数据的改变。
引用是一个别名,在逻辑上不独立,其存在具有依附性,所以必须一开始就被初始化,其引用的对象在其整个生命周期中是不能被改变的,自始至终只能依附于同一个变量。
一、主要区别
引用必须被初始化,但是不分配存储空间。指针不声明时初始化,在初始化的时候需要分配存储空间。
引用初始化后不能被改变,指针可以改变所指的对象。
不存在指向空值的引用,但是存在指向空值的指针。
- 指针传递参数本质上是 值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的 实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。而在引用传递过程中, 被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间 接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
二、代码示例
代码如下(示例), 以下示例程序中,k 被初始化为i 的引用。语句k = j 并不能将k 修改成为j 的引用,只是把k 的值改变成为6.由于k 是i 的引用,所以i 的值也变成了6。
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和i 的值都变成了6;
引用的主要功能是传递函数的参数和返回值。C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。
1.值传递
值传递示例如下,由于Func1 函数体内的x是外部变量n 的一份拷贝,改变x 的值不会影响n, 所以n 的值仍然是0。
void Func1(int x)
{
x = x + 10;
}
int n = 0;
Func1(n);
cout << “n = ” << n << endl;// n = 0
2.指针传递
指针传递示例如下,由于Func2 函数体内的x 是指向外部变量n 的指针,改变该指针的内容将导致n 的值改变,所以n 的值成为10。
void Func2(int *x)
{
(* x) = (* x) + 10;
}
⋯
int n = 0;
Func2(&n);
cout << “n = ” << n << endl; // n = 10
3.引用传递
引用传递示例如下,由于Func3 函数体内的x 是外部变量n 的引用,x和n 是同一个东西,改变x 等于改变n,所以n 的值成为10。
void Func3(int &x)
{
x = x + 10;
}
//...
int n = 0;
Func3(n);
cout << “n = ” << n << endl; // n = 10
总结
指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。
strings1("Nancy");
strings2("Clancy");
string& rs = s1; // rs 引用 s1
string *ps= &s1; // ps 指向 s1
rs = s2; // rs 仍旧引用s1
// 但是s1的值现在是"Clancy"
ps = &s2; // ps 现在指向 s2;// s1 没有改变
总的来说,在以下情况下你应该使用 指针: 一是你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空); 二是你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变 指针的指向)。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么你应该使用引用。 还有一种情况,就是当你重载某个操作符时,你应该使用引用。最普通的例子是操作符[]。这个操作符典型的用法是返回一个目标对象,其能被赋值。