指针和引用

指针和引用的相同:

  1. 引用和指针都是地址的概念,引用是一个内存对象的别名,指针指向一个内存对象,保存了这个对象的内存地址。
  2. 不可以返回局部变量的引用/指针(例如函数返回内部变量的引用/指针)。
    原因是局部变量的生命周期。

指针和引用的不同:

1. 指针是对象,而引用不是对象。

指针是由基础数据类型+变量修饰符*进行声明,代表对应数据类型的指针变量;引用只是通过变量修饰符&对变量起的别名。

1
2
3
int a=3;
int *b=&a; //b是指向整型变量a的指针
int &c=a; //c是整型变量a的别名

由此带来的结果是:不能定义指向引用的指针(引用不是变量),可以定义指针的引用(指针是变量)。

1
2
3
4
int i= 42;
int *p;
int *&r = p; //正确,r是对指针p的引用,变量类型也是指针
int &*s = p; //错误,不可以生成引用类型的指针(因为引用不是变量)

要理解r的类型到底是什么,最简单的办法是从右向左阅读r的定义。离变量名最近的符号(此例中是r的符号)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定x引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个int指针。

2. 引用必须初始化,指针不是。

3. 尽管初始化都不能指向字面值,但引用可以引用常量和变量,指针只能指向变量

1
2
3
4
5
6
//int &ref = 10;  //引用需要初始化、需要一个合法的内存空间,因此这行错误
//加入const就可以了,编译器优化代码:int temp = 10; const int& ref = temp;
const int& ref = 10; //正确,引用可以引用常量和变量

//int *a = &10; //同样错误,指针不需要初始化,但需要指向一个合法的内存空间
//const int *a = &10; //仍然错误,指针只能指向变量

指针和引用的联系:

引用本质实际上通过内部的指针实现,并且可以说引用本质上是一种不允许修改指向的指针。

1
2
3
4
5
6
7
8
9
int a= 10;

//自动转换为 int * const ref = &a;
//指针常量:指针的指向不可更改,也说明了为什么引用不能更改。
int &ref = a;

//内部发现a是引用,自动帮我们转换:*ref = 20;
//不能修改指向,但可以更改指针指向的数据
ref=20;

有了指针为什么还需要引用?
Bjarne Stroustrup(C++之父)的解释:
为了支持函数运算符重载;

有了引用为什么还需要指针?
Bjarne Stroustrup(C++之父)的解释:
为了兼容C语言;
注意:C语言完全用指针,JAVA语言完全用引用。

补充

关于函数传递参数类型的说明:

  • 内置基础类型(如int,double等)而言,在函数中传递pass by value更高效;
  • 对OO面向对象中自定义类型而言,在函数中传递时pass by reference to const更高效。