文章推荐:大话指针
1、为什么要用指针?
指针用于共享内存,常见的数据结构,比如链表,树,正是因为指针的存在才得以实现。
2、为什么要用引用?
引用是C++中的特性,它的作用也是为了共享内存,某些方面上,它要优于指针,因为引用不存在空值,定义时必须初始化,且无法更改的缘故,使用引用更加安全,且引用不占用内存。
3、指针与引用的区别有哪些?
类型 | 初始化 | 可修改性 | 值属性 | 合法性验证 | 应用 |
指针 | 没有初始化要求(但不初始化容易产生野指针) | 可修改 | 可以为空(NULL/nullptr)值 | 因为前面的属性,所以必须验证其合法性 | 常见的数据结构、函数传参、数据共享 |
引用 | 在创建时必须初始化 | 不可修改 | 不存在空值 | 无需验证,因此使用时更安全、高效 | 参数传递 |
4、复杂指针的声明
类型 | 格式 | 样例 |
普通指针 | 所指类型* 变量名 | int *a |
指针的指针 | 所指指针的类型 *变量名(同上) | int **a |
指针(的)数组 | 指针类型 变量名[长度] | int *a[10] |
数组(的)指针 | 数组元素类型 (*变量名)[所指数组长度] | int (*a)[10] |
函数(的)指针 | 函数返回值 (*函数指针名)(参数类型列表) | int (*)(int,int) |
(返回)指针(的)函数 | 函数返回值 函数名(参数列表) | int* fun(int,int) |
总结 | 如果把指针当做一种类型,定义的格式其实跟指针没有太多联系 |
|
5、指针常量与常量指针
与指针数组,数组指针,指针函数,函数指针一样,中间加一个“的”字就很容易理解了
类型 | 样例 | 解读 |
指针常量 | int* const a | const修饰a:说明指针变量a不能修改 |
常量指针 | const int * a | const修饰类型(int*):说明指针存储的是const int类型的地址 |
6、this指针
在C++中,类的任何非静态成员都含有this指针,因为并不是一个对象拥有一套独立的成员函数,对象是通过this指针进行彼此区分,从而调用类的同一个函数。
class MyClass{
public:
MyClass() {}
void print() {
cout << "hello" << endl;
}
};
int main() {
MyClass* a=new MyClass;
a[100].print(); //由于print函数并未用到任何成员数据,故没有使用this指针,因此这行代码不会报错
return 0;
}
7、指针的转换
c语言中只需要在指针变量前用括号加上目标类型,就可以转换,比如 int* a = (int*)1;但由于没有安全性检查,使用它是存在危险的
操作符名称 | 适用场景 |
---|---|
static_cast<>() | 没有运行时类型检查。 c++ 的任何的隐式转换都是使用 static_cast 来实现。 static_cast不能转换掉原有类型的const、volatile、或者 __unaligned属性。 |
reinterpreter_cast<>() | 用在任意的指针或引用间的转换。 |
dynamic_cast<>() | 子类和父类之间的多态类型转换。拥有安全检查 |
const_cast<>() | 去掉指针或引用的const属性。 |
8、野指针的危害
- 越界指向不可访问的地址:触发段错误。
- 越界指向一个可用的,但是暂时没有使用的空间:程序可以正确运行,但是存在隐患。
- 越界指向一个可用的,且正在被使用的空间:修改指针所指内容会产生问题,试想你写了一个银行资金管理系统,别人改一下用户名,因为野指针的缘故,越界修改了资金,那么后果可想而知。