在C++中,const作用于指针时,可以看做是对指针权限的限制。这里我们先把指针的权限归为两种,分别为指向权限和修改权限。(ps:以上是为了理解方便,实际并没有如此规定)
1
2
3
4
5
6
7
8
9
10
|
int a = 10, b = 20; int * p = &a; p = &b; // 改变指向的权限 √ *p = 30; // 修改内存的权限 √ const int * cp = &a; // 限制修改权限 //*cp = 100; // error:表达式必须是可修改的左值 修改 x cp = &b; // ok. 指向 √ int * const pa = &a; // 限制指向权限 *pa = 100; // ok. 修改 √ //pa = &b; // error:表达式必须是可修改的左值 指向 x |
指针的赋值一般遵守权限缩小式的赋值。例如,我有一本书,我有使用权限(我可以看,可以做笔记),借给你后你只有阅读权限(只能看,不能做笔记)。当然,如果我们关系好,我可以赋予你使用权(你拥有读写的权利)。同样的,指针的赋值也是如此。
1
2
3
4
5
6
7
|
int a = 10; int * p = &a; // int* <== int * int * q = p; // int* <== int* const int * cp = p; // const int* <== int* 权限缩小,√ int * const pa = p; // int* <== int* 注意:int* const pa;是“int*”类型 //int* p1 = cp; // error:int* <== const int * 权限放大,x int * p2 = pa; // ok. int* <== int* |
我们可以得出一级指针赋值的公式
1
2
3
|
int * <== int * // int* 包含 int* 和 int* const类型 int const * <== int * // int const * <=等同=> const int * // 以上公式反过来赋值就是错误的.. |
练习一:一级指针指向练习题
题目一:下列表达式语句赋值错误的是?
1
2
3
4
5
6
7
8
9
10
11
12
|
int a = 10; const int * p = &a; int * q = p; int a = 10; int * const p = &a; int * q = p; int a = 10; int * const p = &a; int * const q = p; int a = 10; int * const p = &a; const int * 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
|
int a = 10; const int * p1 = &a; int * q1 = p1; // error:无法从const int * 转为 int * /* 分析: int* <= cosnt int* */ int * const p2 = &a; int * q2 = p2; /* 分析: int* <= int* */ int * const p3 = &a; int * const q3 = p3; /* 分析: int* <= int* */ int * const p4 = &a; const int * 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 int a = 10; int * p1 = &a; const int ** q1 = &p1; // 选项B int a = 10; int * p2 = &a; int * const * q2 = &p2; // 选项C int a = 10; int * p3 = &a; int ** const q3 = &p3; // 选项D int a = 10; int * const p4 = &a; int ** q4 = &p4; // 选项E int a = 10; const int * p5 = &a; int * const * q5 = &p5; |
答案:(鼠标选中查看)
<错误:A、D、E,正确:B、C>
A选项;
错误; 注:如果const修饰的是二级指针,我们需要对二级指针的逐层解引用进行分析。
1
2
|
int * p1 = &a; const int ** 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
|
// 方案一 const int * p12 = &a; const int ** q12 = &p12; // 方案二 int * p11 = &a; const int * 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 ** const q3 = &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
|
int n = 10; // 使用typeid(valtypr).name() 输出变量类型 int const * p1 = &n; // int const * int * const p2 = &n; // int * // 忽略const int * p = &n; int ** q = &p; //int const** q1 = &p; int const * const * q1 = &p; // int const* const* int * const * q2 = &p; // int* const* int ** const q3 = &p; // int** // 忽略cosnt |
D选项;
错误; 同B选项相同,对于const修饰的一级指针进行判即可。
1
2
|
int * const p4 = &a; int ** q4 = &p4; //error "int *const *"类型的值不能用于初始化"int **类型的实体 |
int* const p4 = &a;
类型为 int*
,因为const的存在,取地址后类型为 int * const *
int** q4 = &p4;
类型为 int**
则指针赋值过程为 int** <== int* const*
分析:
-
const作用于(p4),修饰一级指针。则我们忽略没有const修饰的部分。即
* <== const*
,//忽略 int 部分,该部分赋值时权限没有发生变化。int* <== int const *
,给指针确定一个类型,如“int” 类型 - 如上,我们可以看到,该表达式语句想从int const* 类型处,获得一个 int* 类型的赋值,也就是说这是权限放大式的赋值。错误原因:该赋值会使得 int* 类型指针对常量(int const* 所指向的值)产生修改的风险。
修改方案:
-
把
int* <== int const *
型赋值改成int const* <== int const *
类型赋值即,int*const* q4 = &p4;
E选项;
错误; 注:如果赋值两边都有const时,各论各的分析,如下。
1
2
|
const int * p5 = &a; int * const * q5 = &p5; //error 无法从"const int **"转换为"int *const *" |
分析:
-
省略分析过程等赋值类型为
int* const* <== const int* *
-
分情况分析:
-
提取指针左边部分:
int* <== const int*
,错误 x -
提取指针右边部分:
cosnt * <== *
即int const * <== int *
,正确 √
-
提取指针左边部分:
- 综上,错误 x。
修改方案:
1.修改指针左边类型:int* <== const int*
⇒ int* <= int*
2.修改指针左边类型:int* <== const int*
⇒ const int* <= const int*
1
2
3
4
5
6
|
//1 int* <= int* int * p51 = &a; // const int* p5 ⇒ int* p51 int * const * q51 = &p51; //2 const int* <= const int* const int * p52 = &a; const int * const * q52 = &p52; // int* const* q5 ⇒ const int* const* q52 |
方法总结:
对于二级指针的赋值操作判断,看const位置、主要有以下两种情况:
-
如果 const修饰的是二级指针 如:
-
int const **
,如选项A。我们需要考虑其解引用情况。cosnt修饰二级指针所指向的值为常量,但是由于一次解引用后的指针会存在修改常量的风险,因此我们需要限制该指针与常量之间进行过度的一级指针 -
针对此类二级指针,我们只需记住合法的赋值为等式两边需同时有const ,
const int* cosnt* <== int**
或 左边等式有两个cosnt ,const int* cosnt* <== int**
。
-
- 如果 const修饰的是一级指针或其他 如:
1.const修饰的是一级指针,int * const *
,如选项B。单独剥离出含cosnt类型的一级指针类型进行分析
2.即修饰一级指针又修饰二级指针 如, int cosnt * cosnt *
3.无const修饰 如, int**
或 int ** cosnt
,如选项C、选项D
- 针对此类二级指针,通过一级指针的比较进行比较即可。
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/weixin_43919932/article/details/108632601