万古教员有名言,自信人生二百年。
个人主页:oioihoii 喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞!

一、区别
- 基本性质:
- 指针:指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
- 引用:引用并不是一个真正的变量,它只是另一个已存在变量的别名。
- 可变性:
- 指针:指针可以被重新赋值,以指向另一个对象。
- 引用:一旦引用被初始化以引用一个对象,它就不能改变为引用另一个对象。引用必须在创建时被初始化。
- 空值:
- 指针:指针可以为 NULL。
- 引用:引用不能为 NULL。
在 C++ 中,引用不能为 NULL,主要原因是设计者为了保持引用的安全性和一致性。
- 安全性:引用在创建时必须被初始化,并且一旦被初始化后就不能改变引用的对象。这意味着引用总是引用一个有效的对象。如果允许引用为 NULL,那么在使用引用时就需要检查它是否为 NULL,这将增加编程的复杂性和出错的可能性。
- 一致性:在 C++ 中,引用被设计为一个已存在对象的别名,它没有自己的地址和存储空间。如果允许引用为 NULL,那么这个规则将被打破,因为 NULL 是一个特殊的值,表示没有指向任何对象。
- 易用性:引用的主要用途是作为函数的参数和返回值,以提供一种安全和方便的方式来操作数据。如果允许引用为 NULL,那么在使用引用时就需要额外的检查和处理,这将降低编程的效率和便利性。
- 间接性:
- 指针:可以有多级指针(即,指针的指针)。
- 引用:没有“引用的引用”的概念。
在 C++ 中,没有“引用的引用”的概念,主要原因是设计者为了保持语言的简洁性和一致性。
- 简洁性:引用在创建时必须被初始化,并且一旦被初始化后就不能改变引用的对象。这意味着引用总是引用同一个对象,因此没有必要创建“引用的引用”。如果允许“引用的引用”,那么语言的复杂性将增加,因为需要定义和处理更多的规则和特例。
- 一致性:在 C++ 中,引用被设计为一个已存在对象的别名,它没有自己的地址和存储空间。如果存在“引用的引用”,那么这个规则将被打破,因为“引用的引用”将需要有自己的地址和存储空间。
- 安全性:引用的主要用途是作为函数的参数和返回值,以提供一种安全和方便的方式来操作数据。如果允许“引用的引用”,那么可能会引入新的错误和问题,例如,如果一个引用引用另一个引用,然后原始的引用被销毁,那么这个“引用的引用”将引用一个不存在的对象。
- 语法:
- 指针:需要使用 * 运算符来访问指针指向的值。
- 引用:可以像普通变量一样使用引用,不需要额外的运算符。
- 使用场景:
- 指针:通常用于动态内存分配、数组、链表等数据结构和函数参数传递。
- 引用:通常用于函数参数传递和复制构造函数。
二、内存模型
- 指针的内存模型:
- 指针是一个变量,它存储了另一个变量的内存地址。因此,指针本身占用一定的内存空间(在 32 位系统中通常为 4 字节,64 位系统中为 8 字节)。
- 指针变量的值就是它所指向的变量的内存地址,这个地址可以直接用来访问和操作该变量。
- 指针可以被重新赋值,以指向另一个变量,也可以被赋值为 NULL,表示它不指向任何变量。
- 引用的内存模型:
- 引用并不是一个真正的变量,它只是另一个已存在变量的别名。因此,引用本身不占用任何内存空间。
- 引用的内存地址就是它所引用的变量的内存地址,可以直接用来访问和操作该变量。
- 引用一旦被初始化以引用一个对象,就不能改变为引用另一个对象。也就是说,引用总是引用同一个变量,不能被重新赋值。
疑问:引用不占用任何内存,那它的变量名存放在哪里?
在 C++ 中,引用并不是一个独立的实体,而是另一个已存在变量的别名。因此,引用本身并不占用任何内存空间。但是,这并不意味着引用的变量名不存在。实际上,引用的变量名存在于编译器的符号表中。
符号表是编译器用来跟踪程序中各种符号(如变量名、函数名等)的数据结构。当你在代码中声明一个引用时,编译器会在符号表中为这个引用创建一个条目,并将它与它所引用的变量关联起来。然后,在编译和链接过程中,编译器和链接器会使用这个符号表来确定每个引用的位置和值。
因此,虽然引用本身不占用内存,但它的变量名确实存在于编译器的符号表中。在运行时,引用的变量名会被替换为它所引用的变量的地址,因此你可以像使用普通变量一样使用引用。
三、如何选择
通过上面对指针和引用的区别和内存模型的阐述,我们可以归纳总结出以下三点他们在选择时的考虑:
- 必不为空选择引用,可null选择指针:在C++中,引用必须在创建时初始化,并且一旦初始化,就不能更改引用的目标。这意味着引用不能为null,因为null不是一个有效的对象。如果你的函数参数可能为null,那么你应该使用指针,而不是引用。例如:
void func(int* ptr) {
if (ptr) {
// 使用ptr
}
}提问:下面的代码可行吗?
int *a = nullptr; // 或者 int *a = 0; int &b = a;
不可以,在C++中,解引用一个空指针是不安全的,会导致程序崩溃。因此,你应该在解引用一个指针之前,确保它不是空的。
- 可能重新赋值使用指针,否则使用引用:在C++中,指针可以在任何时候改变它所指向的对象。这使得指针在处理动态数据结构(如链表和树)时非常有用。例如:
int a = 10;
int b = 20;
int* ptr = &a; // ptr指向a
ptr = &b; // ptr现在指向b- :为了便捷使用引用的特殊情况:在C++中,你可以通过返回引用来修改函数返回的对象。这在编写像数组下标运算符这样的函数时非常有用。例如:
class MyArray {
private:
int arr[10];
public:
int& operator[](int index) {
return arr[index];
}
};
int main() {
MyArray myArray;
myArray[0] = 10; // 使用我们定义的operator[]来访问和赋值元素
return 0;
}在这个例子中,operator[]返回一个指向arr数组元素的引用,这意味着你可以使用这个运算符来修改数组的元素。例如,myArray[0] = 10;会修改arr数组的第一个元素。
如果你使用指针作为返回值,那情况如下:
class MyArray {
private:
int arr[10];
public:
int* operator[](int index) {
return &arr[index];
}
};
int main() {
MyArray myArray;
*myArray[0] = 10; // 使用我们定义的operator[]来访问和赋值元素
return 0;
}这样写可以,但是不好用,常规我们都是使用引用作为operator[]返回值。
















