一、指针和引用的区别
① 定义和概念
指针:指针是一个变量,其值为另一个变量的地址。指针本质上是存储内存地址的变量
1 | int a = 10; |
引用:引用是一个别名,它为已有的变量创建一个新的名字。引用初始化必须与某个变量绑定,并且一旦绑定之后不能再绑定到其他变量。
1 | int a = 10; |
② 语法差异
指针语法:声明指针时候使用*
符号、获取指针指向的变量的值需要使用解引用操作符*
、需要显式地进行地址赋值。
1 | int a = 10; |
引用的语法:声明引用使用&
符号、引用像普通变量一样使用,不需要使用解引用操作符、引用必须在声明时进行初始化,并且无法更改引用的对象。
1 | int a = 10; |
③ 是否允许为空值
指针可以为nullptr
,这意味着指针不指向任何有效的内存地址。
1 | int* p = nullptr; |
引用必须始终绑定到一个有效的变量。引用不能是空的,因此在创建引用时必须确保它绑定到一个有效的变量。
1 | int a = 10; |
④ 是否可以重新绑定
指针可以在程序执行过程中重新指向不同的变量。指针是动态可变的。
引用一旦绑定了某个变量,就不能再改变引用的对象,引用的绑定是固定的。
⑤ 内存分配
指针是一个独立的变量,它需要占用内存存储地址。因此,指针本身需要内存空间。
1 | int a = 10; |
引用本身不占用额外的内存空间,它只是一个已经存在的变量的别名。引用的实现通常是通过指针来实现的,但从语法上它没有指针的表现。
1 | int a = 10; |
⑥ 使用场景
指针使用于需要动态管理内存、在函数间传递大量数据时,特别是在对象动态分配、链表、树等数据结构的实现
指针可以进行指针运算,例如加减操作,访问数组元素等。
引用 通常用于函数参数传递(尤其是传递大对象或者需要修改参数的情况下),引用使得函数调用更加简介并且避免了拷贝 的开销。
引用常用于返回对象的引用,或者作为输出参数的替代。
⑦ 安全性
指针的安全性较差,容易发生空指针引用、悬挂指针等问题。例如,如果指针在使用后没有及时初始化为nullptr
,可能会访问非法内存。
引用的安全性较高,因为引用始终必须绑定到一个有效对象,且不能为nullptr
, 这减少了访问无效内存的风险。
⑧ 是否可以被常量修饰
指针可以被const
修饰,指针本身、指针指向的内容都可以是常量。
1 | //const 变量类型* 只能指向一个常量 |
1 | //特点:指针的指向不可以改,指针指向的值可以改(内存中的数据可以更改) |
1 | //const 变量类型* const |
1 | const int a{ 100 }; |
引用可以是常量引用,表示不能修改引用的对象,但引用本身无法修改为指向其他对象。
1 | const int& ref = a; // ref是常量引用,不能修改a的值 |
总结
指针
用于动态内存分配、数组、链表等数据结构。
在函数之间传递多个值,或者需要修改函数外部的对象时使用。
可以指向nullptr
,适用于需要进行空指针检查的场景。
可以进行指针运算。
引用
用于函数参数传递,避免不必要的复制,尤其是在处理大型对象时。
用于返回对象的引用,以便函数外部能修改对象。
比指针更加简洁、直观。
不支持空引用,确保引用有效。