C++ 常量指针与指针常量深度解析:const 修饰符的内存安全实践
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:203
- 发布: 2025-07-05 07:17
- 最后更新: 2025-07-07 13:03
概述
常量指针和指针常量的差异
示例
-
常量指针:指向常量的指针,指针指向可以更改,但是指向的值因为是个常量,所以不能更改
c++int a = 10; int b = 20; const int *p = &a; p = &b; // 正确,改变了指向 *p = b; // 错误,不能改变值,值是个常量注意:常量指针做函数参数,可以防止指针指向值在函数内部被修改。
-
指针常量:指针的值是个常量,所以指向不能更改,但是指向的值可以更改
c++int a = 10; int b = 20; int * const p = &a; p = &b; // 错误,不能改变指针指向 *p = b; // 正确,可以改变指针指向的值注意:指针常量做参数,主要用于 out params(函数通过参数向外部传递值),防止指针指向改变
-
const 既修饰指针,又修饰常量:指针的指向,指针的值都不可以更改
c++int a = 10; int b = 20; const int * const p = &a; p = &b; // 错误,不能改指针的指向 *p = b; // 错误,不能改变指向的值
运算
指针的运算不同普通的数值运算,指针运算是与指针的类型息息相关。例如:
c
char *p; *(p + 1) == p[1]; // p + 1 等于指针值 + 1 x sizeof(char)
int *p; *(p + 1) == p[1]; // p + 1 等于指针 p 的值 + 1 x szieof(int)
long long *p; // p + 1 等于 p + 1 x (sizeof(long long)),变化了 8 个字节
p[1] 相当于 *(p + 1),p[n] 相当于 *(p + n),实质其实是相当于对指针的值的一个运算,这个运算涉及到指针的类型。void *类型之所以无法解引用,是因为他没有类型,无法对指针指向的地址处进行取值(不知道类型,解引用后不知道数据的宽度)
多级指针
二级指针 char **p,相当于指针p 指向指针p1,指针p1指向字符的地址。对指针的运算,相当于对目的地址的一个变化,所以二级指针,对 p 进行操作后,将无法再寻得最终的字符。p[0] 相当于 *p。
多维数组的内存分配是一块连续的内存地址,否则将无法进行指针运算。
例如:A[2][3][4],A 的类型是 int (*)[3][4],A[0]的类型是int (*)[4],A[0][0]的类型是int *。A + 1等于移动了int(*)[3][4]的距离,相当于 A地址 + sizeof(int) x 3 x 4。
当一个多级指针指向一个连续分配内存的地址的时候,才能想数组一样进行各级的指针运算。否则,只能进行依次的解引用操作,因为中间的指针进行运算的时候,就会导致无法寻到最后指向的数据。
与汇编的关系
assembly
jmp dword ptr [0x12345678] // 跳转到 0x12345678 内存地址中存储的双字的一个地址。
其中 [地址]这种形式,相当于对一个指针地址进行解引用,但是指针解引用需要指针类型(也就是解引用后取数据的宽度),这个就是中括号前面的关键字dword ptr,表示是双字。