C++指针与引用小结

概念

引用

引用就是某一对象(变量)的一个别名。举个例子更容易理解:

int m;
int &n = m;

这段程序中,nm的一个引用(reference),m是被引用物(referent)。 n相当于m别名(绰号),对n的任何操作就是对m的操作。 n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。

指针

指针用于指向对象(变量)。指针提供对其所指对象的间接访问。指针用于指向单个对象。

(这三句摘自《C++ Primer, Fourth Edition》)。再举个例子:

int m;
int *n = &m;

第二条语句定义了一个指向int型的指针n,并初始化n使其指向int型的变量m*n中的 * 操作符表明n是一个指针变量(n本质上也是一个变量,只不过这个变量的存储内容是 地址)。 &m中的 & 符号是取地址操作符,当此操作符用于一个对象上时,返回的是该对象的存储地址。

联系

区别

这句话从内存分配的角度很好理解,程序会为指针变量分配内存区域,而引用不分配内存区域。

指针在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 引用在逻辑上不独立,具有依附性,所以引用必须在一开始就被初始化,而且引用一旦和某个对象绑定后就不能再改变(从一而终)。

即指针可以为 NULL,而引用必须与合法的存储单元关联。

首先,函数参数和返回值的传递方式大概可以理解为三种:

  1. 值传递
  2. 指针传递
  3. 引用传递

先理解值传递:值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个拷贝。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

指针传递本质上值传递,只不过它所传递的是一个地址值。然后把上面那段话「翻译」一下:指针传递时,形参是一个指针变量,该变量拷贝了实参的地址值,然后作为被调函数的局部变量(传递过来的实参的地址值不会变),再然后我们可以用*操作符访问实参,从而对实参进行操作。很绕口,不如看个例子:

#include <iostream>
using namespace std;
 
void f(int *n)
{
  *n = 5;
}
 
int main()
{
  int m = 1;
  cout << m << endl;
  f(&m);
  cout << m << endl;
 
  return 0;
}

该程序输出结果为:1 5

在函数f中,形参n是指向int型的指针变量,拷贝了实参m的地址,作为f函数的局部变量,然后通过*n改变实参m的值。

而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址(不必通过*操作符),即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量(此时的形参其实就是实参)。再举个例子:

#include <iostream>
using namespace std;
 
void f(int &n)
{
  n = 5;
}
 
int main()
{
  int m = 1;
  cout << m << endl;
  f(m);
  cout << m << endl;
 
  return 0;
}

输出结果为:1 5

nf中的局部变量,同时n也是实参m的引用。此时n就为m,所以在f中对n的操作都会影响m,为n赋值 5 就是对m赋值 5。

还可以从编译角度理解(此处从网上摘录):

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

要理解知识必须先建立知识的结构,就像盖楼房一样,必须先有框架,所以此处附上本人制作的一幅简单的思维导图: