阅读ANSI C标准,寻找乐趣和裨益 
    int foo(const char **p) {
    }
    编译这段代码,编译器会发出一条警告信息: 
    int main(int argc, char **argv) {
        foo(argv);
    }
    /*line 5: warning: argument is incompatible with prototype
    *prototype: pointer to pointer to const char:
    *argument: pointer to pointer to char*/ 
    /*
    ** interest of ansi.
    */
    #include <stdio.h>
    #include <stdlib.h>

int foo( const char **p );

int main( int argc, char *argv[] ){
        /*
        ** foo( argv );
        ** can't pass compilation:
        ** because of [Error] invalid conversion from 'char **' to 'const char **'[-fpermissive]
        ** and [Note] initializing argument 1 of 'int foo(const char **)'
        */
    
        return EXIT_SUCCESS;
    }

int foo( const char **p ){
        return 0;
    }
输出:

实参char *s与形参const char *p应该是相容的,标准库中所有的字符串处理函数都是这样的。
    实参char **argv与形参const char **p实际上不能相容呢?答案是肯定的,它们并不相容。 
    每个实参都应该具有自己的类型,这样他的值就可以赋值给它所对应的形参类型的对象(该对象的类型不能含有限定符)。
    这就是说参数传递过程类似于赋值。所以,除非一个类型为char**的值可以赋值给一个const char**类型的对象,否则肯定会产生一条诊断信息。要想知道这个赋值是否合法,就请回顾标准中有关简单赋值的部分。 
    标准中关于简单赋值的部分 
    *要使上述的赋值形式合法,必须满足下列条件之一:
    *两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须
    *具有右边指针所指向类型的全部限定符。
    //合法: 
    char *cp;
    const char *ccp;
    ccp = cp;
    左操作数是一个指向有const限定符的char的指针,右操作数是一个指向没有限定符的char的指针。char类型与char类型是相容的,左操作数所指向的类型具有右操作数所指向类型的限定符(无),再加上自身的限定符(const)。
    cp = ccp; /*结果产生编译警告*/

const float *类型并不是一个有限定符的类型---它的类型是“指向一个具有const限定符的float类型的指针”,也就是说const限定符是修饰指针所指向的类型,而不是指针本身。
    const char **也是一个没有限定符的指针类型,它的类型是“指向有const限定符的char类型的指针的指针”
    char**和const char **都是没有限定符的指针类型,但它们所指的类型不一样(前者指向char*, 后者指向const char *),所以它们是不相容的。因此,类型为char**的实参与const char **的形参是不相容的。
    可以用下面这个方法进行理解:
    左操作数的类型是FOO2,它是一个指向FOO的指针,而FOO是一个没有限定符的指针,它指向一个带有const限定符的char类型。
    右操作数的类型为BAZ2,它是一个指向BAZ的指针,而BAZ是一个没有限定符的指针,它指向一个没有限定符的char类型。 
    FOO和BAZ所指的类型是相容的,而且他们本身都没有限定符,所以符合标准的约束条件,两者之间赋值是合法的。
    但FOO2和BAZ2之间的关系又有不同,由于相容性是不能传递的,FOO和BAZ所指向的类型相容并不代表FOO2和BAZ2所指向的内容也相容,所以虽然FOO2和BAZ2都没有限定符,但它们之间不能进行赋值。也就是说,它们都是不带限定符的指针但它们所指的对象是不同的,所以它们不能进行赋值,也就不能分别作为函数的形参和实参。

启发 
    关键字const并不能把变量变成常量,const 限定符只是表示这个符号不能被赋值,也就是它的值对于这个符号来说是只读的,但它并不能防止通过程序的内部(甚至是外部)的方法来修改这个值。 
    const最有用之处就是它来限定函数的形参,这样该函数将不会修改实参指针所指的数据,但其他的函数却可能会修改它。这也许就是C和C++中const最一般的用法。 
    const可以用在数据上:
    const int limit = 10;
    limitp 是一个指向常量整数的指针,这个指针不能用于修改这个整数值。但是在任何时候,这个指针本身的值却可以改变。这样,它就指向了不同的的地址,对它进行解除引用(dereference)操作会得到一个不同的值。
    const和*的组合通常只用于在数组形式的参数中模拟传值调用。它声称“我给你一个指向它的指针,但你不能修改它”。
    这个约定类似于从极为常见的void*的用法,尽管在理论上它可以用于任何情形,但通常被限制于把指针从一种类型转换为另一种类型。 
    const int *limitp = &limit;
    int i = 27;
    limitp = &i;  
    类似地,你可以取一个const变量的地址,并且可以......。正如Ken Thompson所指出的那样,“const关键字可能引发一些罕见的错误,只会混淆函数库的接口”。回首往事,const关键字原先如果命名为readonly就好多了。

#include<stdio.h>
    
    int main()
    {
        const int limit = 10;
        printf( "limit = %d\n", limit );
        const int *limitp = &limit;
        printf( "*limitp = %d\n", *limitp );
        /*
        ** *limitp = 12;
        ** can't pass compilation:
        ** because of [Error] assignment of read-only location '*limitp'
        */
        int i = 27;
        printf( "i = %d\n", i );
        void *p = &i;
        *(int *)p = 12;
        printf( "*p = %d, i = %d\n", *(int *)p, i );
        limitp = &i;
        printf( "limit = %d\n", limit );
        printf( "*limitp = %d\n", *limitp );
        printf( "i = %d\n", i );
        
        return 0;
    }

输出:

C专家编程 第1章 C:穿越时空的迷雾 1.9 阅读ANSI C标准,寻找乐趣和裨益相关推荐

  1. 《C专家编程》一1.9 阅读ANSI C标准,寻找乐趣和裨益

    本节书摘来自异步社区<C专家编程>一书中的第1章,第1.9节,作者 [美]Perter Van Der Linde,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...

  2. C专家编程 第1章 C:穿越时空的迷雾 1.4 KR C

    时间:1978 人物:Steve Johnson 事件:编写了pcc这个可移植的C编译器 影响:形成了一代C编译器的基础. C语言的演化之路如图1-2所示. 1973-3(早期的C)--->19 ...

  3. C专家编程 第6章 运动的诗章:运行时数据结构 6.1 a.out及其传说

    运动的诗章:运行时数据结构      编程语言理论的经典对立之一就是代码和数据的区别.有些语言(如Lisp)把二者视为一体.其他语言(如C语言)通常维持两者的区别.Internet蠕虫非常难以被人们所 ...

  4. 《C专家编程》第二章——这不是Bug,而是语言特性

    无论一门语言有多么流行或多么优秀,它总是存在一些问题,C语言也不例外.本章讨论的重点是C语言本身存在的问题,作者煞费苦心的用一个太空任务和软件的故事开头,也用另一个太空任务和软件的故事结尾,引人入胜. ...

  5. C专家编程 第11章 你懂得C,所以C++不再话下 11.1 初识OOP

    C++之于C,就像Algol-68之于Algol          ---David L.Jones     如果你觉得C++还不够复杂,那你知道protected abstract virtual ...

  6. C专家编程 第10章 再论指针 10.7 使用指针创建和使用动态数组

    使用指针创建和使用动态数组     当预先并不知道数据的长度时,可以使用动态数组.绝大多数具有数组的编程语言都能够在运行时设置数组的长度.它们允许程序员计算需要处理的元素的数目,然后创建一个刚好能容纳 ...

  7. C专家编程 第8章 为什么程序员无法分清万圣节和圣诞节 8.2 根据位模式构筑图形

    根据位模式构筑图形     图标(icon)或者图形(glyph)是一种小型的位模式映射于屏幕后产生的图像.一个位表示图像上的一个像素.如果一个位被设置,那么它所代表的像素就是"亮" ...

  8. 《C专家编程》1-2章阅读收获

    一. C诡异离奇,缺陷重重,却获得了巨大的成功. ·编译器设计:效率(几乎)就是一切.编译器的效率包括两个方面:运行效率(代码的运行速度)和编译效率(产生可执行代码的速度). 除了开发和学习环境外,运 ...

  9. C专家编程 第6章 运动的诗章:运行时数据结构 6.3 操作系统在a.out文件里干了些什么

    操作系统在a.out文件里干了些什么      为什么a.out要以段的形式组织.段可以方便地映射到链接器在运行时可以直接载入的对象中!载入器只是取文件中的每个段的映像,并直接将它们放入到内存中.从本 ...

最新文章

  1. 新浪微博登录接口实例
  2. 董明珠:别嫌工资少,满足这些条件!多高都给你
  3. linux /etc/hosts.allow和/etc/hosts.deny 限制 禁止 ip连接 黑名单 白名单
  4. js中关于带数字类型参数传参丢失首位数字0问题
  5. mybatis里的日志动态代理
  6. 带学生参加电赛,5个国一,2个国二!15个省奖!
  7. Android SDK 和 JDK 安装
  8. python狗屁不通文章生成器_狗屁不通文章生成器,哈哈哈
  9. PS图片删除需要计算机管理权限,电脑打开ps,显示没有管理员权限
  10. 金格HTML签章集成
  11. 计算机专业问卷调查,大学生计算机专业调查问卷.doc
  12. web编程1–用户注册之文本框应用,coon连接,存入mysql
  13. java中赛场统分的情况
  14. 用java给pdf压缩并加密_Java实现多文件压缩加密并重命名压缩文件对象的方法
  15. 道可道,非常道;名可名,非常名
  16. SM-G9008V Root,google框架安装 设置开发者模式
  17. 熊猫的python小课_朋友圈里那个可爱的小熊猫Python编程的学习笔记,学编程,不难!...
  18. 利用Invoke-Obfuscation混淆ps文件实现上线/VT免杀率3/55
  19. 计算机一级B考试总结500字,月考总结作文500字(通用11篇)
  20. LightOJ 1319 - Monkey Tradition CRT除数互质版

热门文章

  1. FreeRTOS学习笔记(7)——软件定时器
  2. 怎么把短视频做成gif图?短视频生成gif的步骤
  3. 樱花大战常见问题解答
  4. ajax无刷新kesion,Kesion cms注入漏洞分析及其修复方案
  5. 频率响应范围测试软件,关于示波器频率响应分析仪选件和伯德图测试的区别和发展分析...
  6. ps真实辉光插件:Oniric Glow Generator汉化版
  7. css中的rgba() 兼容IE8以下的浏览器
  8. HTML常用标签或属性全称
  9. html解决div用了fixed后滚动条显示不完整的问题
  10. 浅谈如何正确选择及使用电流互感器