引用(reference)和指针(pointer)都是 C++ 中用来间接访问内存中对象的机制,但它们有一些重要的区别。以下是它们在语法、用法和特性上的详细区别。
下面从7个方面来详细说明引用和指针的区别
1. 定义与语法区别
- 引用(reference) 是某个变量的别名。它在声明时必须被初始化,并且初始化后不能改变引用的目标。
- 指针(pointer) 是一个变量,它存储另一个变量的内存地址。指针可以在运行时被重新赋值,并且可以为空(
nullptr
)。int a = 10; int &ref = a; // ref 是 a 的引用 int a = 10; int *ptr = &a; // ptr 是指向 a 的指针
2. 初始化与重新赋值
-
引用必须在声明时进行初始化,并且一旦引用了某个变量,就不能再引用其他变量。引用不能指向
nullptr
,它必须始终有效。 -
指针可以在声明时不初始化,并且可以在任何时候指向不同的对象。指针可以是空指针(
nullptr
或NULL
),即指向无效的内存。int x = 5; int &ref = x; // 引用必须在声明时初始化 ref = 10; // 改变的是 x 的值 int x = 5; int y = 10; int *ptr; // 可以不初始化 ptr = &x; // 指向 x 的地址 ptr = &y; // 重新指向 y 的地址
3. 访问对象的方式
-
引用直接使用对象的名字来访问所引用的对象,无需解引用。
-
指针需要使用解引用运算符
*
来访问指针所指向的对象。int x = 5; int &ref = x; // ref 是 x 的引用 std::cout << ref << std::endl; // 直接访问 x 的值 int x = 5; int *ptr = &x; std::cout << *ptr << std::endl; // 通过解引用访问 x 的值
4. 内存地址的访问
-
引用本身没有自己的内存地址,它只是所引用对象的别名。你不能获取引用本身的地址,只能获取它所引用的对象的地址。
-
指针有自己的内存地址,并且存储的是它所指向对象的内存地址。你可以获取指针的地址,也可以获取它指向的对象的地址。
int x = 5;
int &ref = x;
std::cout << &ref << std::endl; // 输出的是 x 的地址
int x = 5;
int *ptr = &x;
std::cout << ptr << std::endl; // 输出的是指针存储的 x 的地址
std::cout << &ptr << std::endl; // 输出的是指针本身的地址
5. 指向空值或无效值
-
引用不能指向
nullptr
或者无效的对象。它在声明时就必须引用有效的对象。 -
指针可以是
nullptr
,表示不指向任何对象,或者指向无效的内存地址(虽然指向无效地址是危险的)。int &ref = nullptr; // 错误!引用不能为 nullptr int *ptr = nullptr; // 指针可以为 nullptr
6. 修改所指对象的值
-
引用可以修改所引用对象的值,引用本质上就是对该对象的直接访问。
-
指针可以通过解引用来修改所指对象的值。
int x = 5; int &ref = x; ref = 10; // x 的值被修改为 10 int x = 5; int *ptr = &x; *ptr = 10; // 通过解引用修改 x 的值为 10
7. 常量引用与指针
-
常量引用(
const
reference):常量引用允许引用一个对象,但不允许修改它的值。常用于函数参数中,避免拷贝对象,但又能确保函数不会修改对象。 -
常量指针与指向常量的指针:
-
指向常量的指针:指针可以指向一个常量对象,不能通过指针修改对象的值。
-
常量指针:指针本身是常量,不能改变指针指向的地址,但可以修改指向对象的值。
-
int x = 5; const int &ref = x; // ref = 10; // 错误,不能通过 const 引用修改值 const int x = 5; const int *ptr = &x; // *ptr = 10; // 错误,不能通过指向常量的指针修改值 int x = 5; int *const ptr = &x; *ptr = 10; // 可以修改 x 的值 // ptr = &y; // 错误,不能修改 ptr 指向的地址