在C++中,const作用于指针时,可以看做是对指针权限的限制。这里我们先把指针的权限归为两种,分别为指向权限和修改权限。(ps:以上是为了理解方便,实际并没有如此规定)
1 2 3 4 5 6 7 8 9 10 | inta = 10, b = 20;
int* p = &a;
p = &b;// 改变指向的权限 ✔
*p = 30;// 修改内存的权限 ✔
constint* cp = &a;// 限制修改权限
//*cp = 100; // error:表达式必须是可修改的左值 修改 ✖
cp = &b;// ok. 指向 ✔
int*constpa = &a;// 限制指向权限
*pa = 100;// ok. 修改 ✔
//pa = &b; // error:表达式必须是可修改的左值 指向 ✖
|
指针的赋值一般遵守权限缩小式的赋值。例如,我有一本书,我有使用权限(我可以看,可以做笔记),借给你后你只有阅读权限(只能看,不能做笔记)。当然,如果我们关系好,我可以赋予你使用权(你拥有读写的权利)。同样的,指针的赋值也是如此。
1 2 3 4 5 6 7 | inta = 10;
int* p = &a;// int* <== int *
int* q = p;// int* <== int*
constint* cp = p;// const int* <== int* 权限缩小,✔
int*constpa = p;// int* <== int* 注意:int* const pa;是“int*”类型
//int* p1 = cp; // error:int* <== const int * 权限放大,✖
int* p2 = pa;// ok. int* <== int*
|
我们可以得出一级指针赋值的公式
1 2 3 | int* <==int*// int* 包含 int* 和 int* const类型
intconst* <==int*// int const * <=等同=> const int *
// 以上公式反过来赋值就是错误的..
|
练习一:一级指针指向练习题
题目一:下列表达式语句赋值错误的是?
1 2 3 4 5 6 7 8 9 10 11 12 | inta = 10;
constint* p = &a;
int* q = p;
inta = 10;
int*constp = &a;
int* q = p;
inta = 10;
int*constp = &a;
int*constq = p;
inta = 10;
int*constp = &a;
constint* q = p;
|
答案:(鼠标选中查看)
👉错误:A,正确:B、C、D👈
解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | inta = 10;
constint* p1 = &a;
int* q1 = p1;// error:无法从const int * 转为 int *
/* 分析:
int* <= cosnt int*
*/
int*constp2 = &a;
int* q2 = p2;
/* 分析:
int* <= int*
*/
int*constp3 = &a;
int*constq3 = p3;
/* 分析:
int* <= int*
*/
int*constp4 = &a;
constint* q4 = p4;
/* 分析:
cosnt int* <= int*
*/
|
练习二:二级指针指向练习题
题目二:下列表达式语句错误的有。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 选项A
inta = 10;
int* p1 = &a;
constint** q1 = &p1;
// 选项B
inta = 10;
int* p2 = &a;
int*const* q2 = &p2;
// 选项C
inta = 10;
int* p3 = &a;
int**constq3 = &p3;
// 选项D
inta = 10;
int*constp4 = &a;
int** q4 = &p4;
// 选项E
inta = 10;
constint* p5 = &a;
int*const* q5 = &p5;
|
答案:(鼠标选中查看)
👉错误:A、D、E,正确:B、C👈
A选项;
错误; 注:如果const修饰的是二级指针,我们需要对二级指针的逐层解引用进行分析。
1 2 | int* p1 = &a;
constint** q1 = &p1;//error 无法从“int * *”转换为“const int** ”
|
int* p1 = &a;p1的类型为int*取地址为int **const int** q1 = &p1;q1的类型为const int **则指针赋值过程为const int ** <= int* *
分析:
- const作用于(**q1),修饰二级指针。表示不可通过q1对
a的值进行修改。 - *q1解引用一次后,为一级指针,即p1。但是p1存在对
a修改的风险,因此无法直接赋值。
修改方案:
- 方案一:直接限定一级指针p1。保证p1不会修改a的值,即
const int * p1= &a;const int** q1 = &p1; - 方案二:间接限定q1,使其指向时缩小权限,对解引用后的(*q1)修改的权限做出限制,如:
const int * const * q1;
1 2 3 4 5 6 7 | // 方案一
constint* p12 = &a;
constint** q12 = &p12;
// 方案二
int* p11 = &a;
constint*const* q11 = &p1;
|
B选项;
正确; 注:如果const修饰的是一级指针,我们可以抛开二级指针的表象,但看一级指针的赋值操作是否正确。如本例。
1 2 3 4 5 6 7 8 9 | int* p2 = &a;
int*const* q2 = &p2;
/* 分析:
int* const* <== int* *
const修饰 *q2,即cosnt修饰一级指针
cosnt* <== * // 去掉前面的 int* <= int*
int const * <== int * // 添加一个任意类型,如int
如👆所示,这是一个权限缩小的一级指针赋值,✔
*/
|
C选项;
正确; 注:如果两边类型相同,则无需进行判断。如本例。
1 2 3 4 5 6 7 | int* p3 = &a;
int**constq3 = &p3;
cout <<typeid(q3).name() << endl;//输出 q3 类型 int * *
/* 分析:
int**const <== int* * 即 int** <== int* *
两边类型相同,无需进行特殊判断,✔
*/
|
ps:如果const修饰的参数右边无“*”号,则该cosnt不作用于类型。如:
1 2 3 4 5 6 7 8 9 10 | intn = 10;
// 使用typeid(valtypr).name() 输出变量类型
intconst* p1 = &n;// int const *
int*constp2 = &n;// int * // 忽略const
int* p = &n;
int** q = &p;
//int const** q1 = &p;
intconst*const* q1 = &p;// int const* const*
int*const* q2 = &p;// int* const*
int**constq3 = &p;// int** // 忽略cosnt
|
D选项;
错误; 同B选项相同,对于const修饰的一级指针进行判即可。
1 2 | int*constp4 = &a;
int** q4 = &p4;//error "int *const *"类型的值不能用于初始化"int **类型的实体
|
int* const p4 = &a;类型为int*,因为const的存在,取地址后类型为int * const *int** q4 = &p4;类型为int**则指针赋值过程为int** <== int* const*