• 【学习笔记】指向常量的指针和常量指针


    指针常量

    指针常量是指向常量的指针,即 pointer to const,即指针指向的是一个常量你应该把这个词(指向常量的指针)当做一个整体来理解,而不是分开。(当然也有翻译成指针常量的,但我并不喜欢这种翻译方式)

    通常也将指针本身是一个常量称为顶层 const,将指针所指的对象是个常量称为底层 const
    关系总结如下

    1. 常量指针 = * const = 顶层 const
    2. 指向常量的指针 = const * = 底层 const

    它的语法格式是 const 在 * 左边,这一点很重要,因为后面要讲的常量指针是 const 在 * 的右边。下面是它的基本语法格式

       const double pi = 3.14;   // pi 是一个常量
       const double *cptr = π // cptr 是一个指向常量的指针
       
       // 或者,它的另一种写法是交换一下 const 和 double 的位置顺序
       
       double const *cptr = π // cptr 是一个指向常量的指针
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    它的含义是,不能修改指针指向的内容,比如这里 cptr 指向 pi,不能通过 cptr 修改 pi 的内容。

    下面我们举一个例子来进行具体的讲解

    #include 
    using namespace std;
    
    int main()
    {
       const double pi = 3.14;   // pi 是一个常量
       const double *cptr = π // cptr 是一个指向常量的指针
       cout <<  *cptr << endl;   // 3.14
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里有一个常量 pi,我用 cptr 这个指向常量的指针来指向它,它的内存示意图应该如下
    在这里插入图片描述
    【注】当我说指针的值(内容)的时候,我说的是 0x456。当我说指针指向的值(内容),我说的是 3.14,下面的语境请随着具体上下文自动脑修。

    关于指针常量的两个扩展:
    第一个是我们用普通的指针不能指向这个常量

       const double pi = 3.14; // pi 是一个常量
       double *pnormal = &pi;    // 用普通指针指向常量 pi
    	
    	// error: invalid conversion from ‘const double*’ to ‘double*’
       return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    答案显然是不行的,报错提示这是一个非法类型转换

    事实上,有这样的一个指向关系,指向常量的指针可以指向常量和非常量,而普通指针只能指向非常量,如下图所示。
    在这里插入图片描述
    对上图,从逻辑上是这么理解的,假设一个普通指针 common_pointer 指向且只能指向非常量 non_const_var,通过对 common_pointer 的解引用,我们可以修改非常量 non_const_var 的值。但是如果普通指针 common_pointer 指向一个常量 const_var,理论上来说,可以对普通指针 common_pointer 解引用而修改常量 const_var 的值,但常量又不能修改,所以普通指针只能指向非常量。

    对于常量指针的逻辑亦是如此。

    那么第二个问题是,cptr 指针指向的内容可以修改吗?显然也是不能修改的,因为它此时指向的是一个常量

       const double pi = 3.14;   // pi 是一个常量
       const double *cptr = &pi; // cptr 是一个指向常量的指针
       cout <<  *cptr << endl;   // 3.14
       *cptr = 9.8;              // error: assignment of read-only location ‘* cptr’
       return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到报错的提示是, cptr 具有只读属性。特别的是,即使 cptr 指向的是非常量,它也不能修改这个非常量的内容(如下代码),仅记住一点即可,那就是 cptr 自己本身具有的属性就是只读的

       double pi = 3.14;   // pi 是一个变量
       const double *cptr = &pi; // cptr 是一个指向常量的指针
       cout <<  *cptr << endl;   // 3.14
       *cptr = 9.8;              // error: assignment of read-only location ‘* cptr’
    
    • 1
    • 2
    • 3
    • 4

    虽然指针常量不能修改指向地址的值,但是它可以修改指向的地址,如下可以看到指针常量 a 先指向 b 的地址,之后有成功指向 c 的地址

    #include 
    using namespace std;
    
    int main()
    {
    	int b = 10;
    	int c = 20;
        const int* a = &b;
    	cout << *a << endl; // 10
    	a = &c;
    	cout << *a << endl; // 20
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    常量指针

    常量指针寓意着指针本身的内容不能被修改。它的语法是 const 在 * 的右边:char *const p = greeting;

    你可以这么理解它的含义,很多时候,我们可以对指针进行递增(减)操作,来移动它在内存中的位置,常量指针就是指不能进行这样的移动。

    下面我们用一张图来解释什么叫“指针的值(指针本身的内容)不能被修改”
    在这里插入图片描述
    虽然这幅图已经说明了一切,但我们还是不妨用代码来进一步解释

    #include 
    using namespace std;
    
    int main()
    {
       double pi = 3.14;          // pi 是一个变量
       double e = 2.71;           // e 是一个变量
       double *const cptr = &pi;  // cptr 本身的内容不能改变
       cout <<  *cptr << endl;    // 3.14
       cptr = &e;                 // error: assignment of read-only variable ‘cptr’
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上面的代码中,cptr 本来是指向 pi,但是当 cptr 转而指向 e 的时候就会报错,因为 cptr 作为指针,它是常量的,它的内容是不可以改变的。

    但是 cptr 指向的内容却是可以改变的,这和 pointer to const 不同

       double pi = 3.14;          // pi 是一个变量
       double e = 2.71;           // e 是一个变量
       double *const cptr = &pi;  // cptr 本身的内容不能改变
       cout <<  *cptr << endl;    // 3.14
       *cptr = e;        
       cout <<  *cptr << endl;    // 2.71
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看到在执行完上面的程序后,cptr 指向的值(内容)发生了改变。

    对比指向常量的指针与常量指针

    也许直接记忆中文的话会很容易绕进去,不如直接记忆它们各自对应的英文会要很多,即指向常量的指针是 pointer to const,常量指针是 const pointer。

    对于 pointer to const 来说,显然指针指向的是一个常量(当然它也可以指向一个非常量),对于 const pointer 来说,显然它自己是一个常量,即这个指针是一个常量,它蕴含的意思是这个指针指向的地址永远不可以改变,就好像你永远住在 xx 省 xx 市 xx 路 xx 号一样。

    最后还是用一幅图来解释二者的联系与区别
    在这里插入图片描述
    红色区域是不能改变的值。

    【注】在这幅图中,如果我们把 pi 改为非常量,即 double pi = 3.14; 的形式,虽然依旧不能通过 cptr 来修改它的值,如 *cptr = 2.71 // error,但是可以直接修改 pi 的值是没问题的,如 pi = 2.71; // right。这一点我已经在上面的部分讲过,但在这里还想重复提一下。

    #include 
    using namespace std;
    
    int main()
    {
       double pi = 3.14;
       const double *cptr = &pi;
       cout << *cptr << endl; // 3.14
       // *cptr = 2.71; error
       pi = 2.71;
       cout << *cptr << endl; // 2.71
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    拓展

    现在我们思考这样一个问题,存在以下代码,它能否通过编译呢?

    int main()
    {
        char c = 'c';
    	char* pc;
    	pc = &c;
    	const char** pcc = &pc;
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    事实是不能的,在 const char** pcc = &pc; 位置会报错 error: invalid conversion from ‘char**’ to ‘const char**’。原因是,我们的二重指针是 const 的,当 pcc 通过 pc 指向 c 后,逻辑上,我们不希望通过 pcc 来改变 c,但是,pcc 在指向 pc 的时候,pc 不是 const 的,意味着 pc 可以随时改变指针的指向。

    上面的代码将 pc 设置为 const 就可以正常运行了

    int main()
    {
        char c = 'c';
    	const char* pc;
    	pc = &c;
    	const char** pcc = &pc;
    	
    	c = 'a';
    	cout << c << endl; // a
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    参考

    1. 《Primer C++》
    2. 《C++ 面向对象高效编程》
    3. 简述指针常量与常量指针的区别
  • 相关阅读:
    K8S入门前奏之VMware虚拟机网络配置
    路由vue-router(二)
    单元测试的时候读不到resources.test中配置
    鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    2022-2028年全球与中国不可吸收PEEK缝合锚市场现状及未来发展趋势分析报告
    游戏出海欧洲有哪些可以接入的支付渠道
    深入理解Java正则表达式及其应用
    npm更新包时This operation requires a one-time password.
    【探索Linux】—— 强大的命令行工具 P.15(进程间通信 —— system V共享内存)
    opencv中两个LSD直线检测算法的区别与应用
  • 原文地址:https://blog.csdn.net/qq_34902437/article/details/126481727