0%

Cplusplus13常见的问题

一、指针和引用的区别

① 定义和概念

指针:指针是一个变量,其值为另一个变量的地址。指针本质上是存储内存地址的变量

1
2
int a = 10;
int* p = &a; // p 是指针,存储a的地址

引用:引用是一个别名,它为已有的变量创建一个新的名字。引用初始化必须与某个变量绑定,并且一旦绑定之后不能再绑定到其他变量。

1
2
int a  = 10;
int& ref = a; // ref是 a的引用,相当于a的别名。

② 语法差异

指针语法:声明指针时候使用*符号、获取指针指向的变量的值需要使用解引用操作符*、需要显式地进行地址赋值。

1
2
3
int a = 10;
int* p = &a; // &a 表示获取a的地址
int value = *p; // *p表示解引用,得到a的值

引用的语法:声明引用使用&符号、引用像普通变量一样使用,不需要使用解引用操作符、引用必须在声明时进行初始化,并且无法更改引用的对象。

1
2
3
int a = 10;
int& ref = a; // ref 是 a 的引用
ref = 20; // 改变a的值为20

③ 是否允许为空值

指针可以为nullptr,这意味着指针不指向任何有效的内存地址。

1
int* p = nullptr;

引用必须始终绑定到一个有效的变量。引用不能是空的,因此在创建引用时必须确保它绑定到一个有效的变量。

1
2
int a = 10;
int& ref = a; // ref必须引用一个已初始化的变量

④ 是否可以重新绑定

​ 指针可以在程序执行过程中重新指向不同的变量。指针是动态可变的。

​ 引用一旦绑定了某个变量,就不能再改变引用的对象,引用的绑定是固定的。

⑤ 内存分配

指针是一个独立的变量,它需要占用内存存储地址。因此,指针本身需要内存空间。

1
2
int a = 10;
int* p = &a; // p是指针,需要为p分配内存空间

引用本身不占用额外的内存空间,它只是一个已经存在的变量的别名。引用的实现通常是通过指针来实现的,但从语法上它没有指针的表现。

1
2
int a = 10;
int& ref = a; // ref只是a的别名,不需要额外的内存

⑥ 使用场景

指针使用于需要动态管理内存、在函数间传递大量数据时,特别是在对象动态分配、链表、树等数据结构的实现

指针可以进行指针运算,例如加减操作,访问数组元素等。

引用 通常用于函数参数传递(尤其是传递大对象或者需要修改参数的情况下),引用使得函数调用更加简介并且避免了拷贝 的开销。

引用常用于返回对象的引用,或者作为输出参数的替代。

⑦ 安全性

指针的安全性较差,容易发生空指针引用、悬挂指针等问题。例如,如果指针在使用后没有及时初始化为nullptr,可能会访问非法内存。

引用的安全性较高,因为引用始终必须绑定到一个有效对象,且不能为nullptr , 这减少了访问无效内存的风险。

⑧ 是否可以被常量修饰

指针可以被const修饰,指针本身、指针指向的内容都可以是常量。

1
2
3
4
5
6
7
8
9
10
11
//const 变量类型*  只能指向一个常量
// 特点,指针的指向可以修改,但是指针指向的值不可以修改
const int a{ 100 };
const int b{ 200 };
int c{ 300 };
const int* p{ &a };
// *p = 500; 不可以修改值
std::cout << *p << std::endl;
p = &b; // 可以修改指向
p = &c; // 常量指针也可以指向非常量变量
// *p = 2000; 常量指针就是不让改
1
2
3
4
5
6
7
//特点:指针的指向不可以改,指针指向的值可以改(内存中的数据可以更改)
int a{ 100 };
int b{ 200 };
int* const p{ &a };
//p = &b; 不能修改指向
*p = 999; //可以修改指针指向的内存空间
std::cout << a << std::endl; // 这时候a输出 999;
1
2
3
4
5
6
7
//const 变量类型* const
//特点:指针的指向和指针指向的值都不可以修改
const int a{ 100 };
const int b{ 200 };
const int* const p{ &a };
//p = &b; 不能修改指向
//*p = 999; 不能修改内存空间里面的值
1
2
3
4
5
6
const int a{ 100 };
const int b{ 200 };
//int* pa{ &a }; 常量
int* pa{ (int*)&a }; //通过转换是可以的
*p = 9500; //这种操作是允许的,但是a的值不变
std::cout << *pa << std::endl;

引用可以是常量引用,表示不能修改引用的对象,但引用本身无法修改为指向其他对象。

1
const int& ref = a;  // ref是常量引用,不能修改a的值

总结

指针

​ 用于动态内存分配、数组、链表等数据结构。

​ 在函数之间传递多个值,或者需要修改函数外部的对象时使用。

​ 可以指向nullptr,适用于需要进行空指针检查的场景。

​ 可以进行指针运算。

引用

​ 用于函数参数传递,避免不必要的复制,尤其是在处理大型对象时。

​ 用于返回对象的引用,以便函数外部能修改对象。

​ 比指针更加简洁、直观。

​ 不支持空引用,确保引用有效。