服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 一起来练习C++的指针

一起来练习C++的指针

2022-10-13 14:31我叫RT C/C++

这篇文章主要为大家详细介绍了C++的指针,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

在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

延伸 · 阅读

精彩推荐