一、初始化要求
• 引用:必须初始化,且一旦绑定到某个变量后不可更改
int rats = 101;
int& rodents = rats; // 必须初始化
// int& bad_ref; // 错误!未初始化
• 指针:可以声明后初始化,也可以指向不同的变量。
int* pt; // 合法,但未初始化
pt = &rats; // 后续可赋值
pt = &bunnies; // 合法,指向新变量
二、别名 vs 指针变量
• 引用:是目标变量的别名,二者共享同一内存地址,对引用的操作即对原变量的操作。
rodents++; // 等价于 rats++
// rats和rodents的地址相同(&rodents == &rats)
• 指针:存储目标变量的地址,需通过解引用操作*访问目标。
pt = &rats; // pt存储rats的地址
(*pt)++; // 等价于 rats++
三、地址与值操作
• 引用:&在声明时是类型修饰符(如int&),使用时&ref表示获取原变量的地址。
int rats = 101;
int& rodents = rats;
std::cout << &rodents; // 输出rats的地址
• 指针:&是取地址运算符,*是解引用运算符。
int* pt = &rats;
std::cout << pt; // 输出地址
std::cout << *pt; // 输出值(101)
四、 NULL状态
• 引用:必须绑定到有效变量,不存在空引用。
• 指针:可以指向nullptr或无效地址。
int* pt = nullptr; // 合法
int& ref = *pt; // 未定义行为(危险!)
五、函数参数传递
• 引用参数:函数内部对参数的修改直接影响原变量(按引用传递)。
void swapr(int& a, int& b) { // 引用参数
int temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
swapr(x, y); // x和y的值被交换
• 指针参数:需显式解引用才能修改原变量(按地址传递)。
void swapp(int* a, int* b) { // 指针参数
int temp = *a;
*a = *b;
*b = temp;
}
swapp(&x, &y); // x和y的值被交换
六. 代码可读性
• 引用:语法更简洁,无需*和&操作符,适合需要“别名”的场景。
• 指针:显式操作地址,适合需要动态内存管理或复杂指针运算的场景。
总结对比表
特性 | 引用(Reference) | 指针(Pointer) |
---|---|---|
初始化要求 | 必须初始化 | 可延迟初始化 |
重新绑定 | 不可更改指向 | 可指向不同变量 |
解引用操作 | 无需*,直接操作原变量 | 需*解引用 |
解引用操作 | 无需*,直接操作原变量 | 需*解引用 |
地址获取 | &ref等价于原变量地址 | pt存储地址 |
NULL状态 | 不可为空 | 可为空(nullptr) |
典型用途 | 函数参数、对象别名 | 动态内存、复杂数据结构 |
示例代码
#include <iostream>
using namespace std;
int main() {
int rats = 101;
int& rodents = rats; // 引用初始化
int* pt = &rats; // 指针初始化
cout << "初始值:" << endl;
cout << "rats = " << rats << ", address = " << &rats << endl;
cout << "rodents = " << rodents << ", address = " << &rodents << endl;
cout << "*pt = " << *pt << ", pt = " << pt << endl;
rodents++; // 等价于 rats++
(*pt)++; // 等价于 rats++
cout << "
修改后:" << endl;
cout << "rats = " << rats << endl; // 输出103
cout << "rodents = " << rodents << endl;
cout << "*pt = " << *pt << endl;
pt = nullptr; // 指针可指向nullptr
// rodents = nullptr; // 错误!引用不可为nullptr
return 0;
}
通过上述对比,可以看出引用更像目标变量的“别名”,而指针是独立的变量,存储目标地址。理解两者的差异有助于避免常见错误(如误用引用或未初始化指针)。