zoukankan      html  css  js  c++  java
  • 《C专家编程》读书记录

    其实,这本书适合没事的时候翻翻,随便打开哪一页,应该都可以看下去的。总体来说,写的比较欢脱,不像《C和指针》和《C陷阱和缺陷》的章节标题那么严肃,有时候还以为自己在看科技杂志。不过,理解书里面的内容反而需要有较高的C语言基础,内容结构比较松散,如果觉得没有逻辑性,可能是语言基础还掌握的不够。

    比较喜欢第1章关于C语言的介绍,前世今生什么的。

    2015年5月1日  星期五 天气 雨

    第1章  C:穿越时空的迷雾

    • C语言的史前阶段:BCPL->B->New B->早期C
    • C语言的早期体验(评:历史原因造成了现在C语言的一些语言特性)
    • 标准I/O库和C预处理器
    • K&R C   

          

    • 今日之ANSI C
    • 它很棒,但符合标准吗:不可移植代码,坏代码,可移植代码
    • 编译限制,ANSI C标准对一个能够成功编译的程序的最小长度做了限制
    • ANSI C标准的结构,与K&R C相比,最重要的新特性就是原型

    第2章 这不是Bug,而是语言特性f

    • 编程语言的细节,Fortran语言经典错误,DO 10 I=1.10和DO 10 I=1,10的区别。

        分析编程语言缺陷的一种方法是把所有的缺陷归类为3类:不该做的做了,该做的没做,该做但做的不合适。

    • 多做之过
      • switch语句中的fall through  
      • 相邻字符串常量被自动合并  
      • 太多的缺省可见性,即默认的函数作用域过宽
    • 误做之过,语言中有误导性质或是不适当的特性
      • 重载,许多符号甚至关键字被重载
      • 有些运算符的优先级是错误的(ANSI C标准由于种种历史原因,没有在优先级方面采取措施)
    • 少做之过,语言应该提供但未能提供的特性
      • 空格问题
      • 注释风格
      • 编译器日期被破坏
      • lint程序绝不应该被分离出来,lint程序寻找bug,早用,勤用

    第3章 分析C语言的声明

    • 只有编译器才会喜欢的语言,声明
    • 声明如何形成,至少一个类型说明符+有且只有一个声明器+零个或更多声明器+一个分号
    • 优先级规则,括号内的->后缀操作符->前缀操作符,按照这个顺序优先级从高到低
    • 通过图表分析C语言声明
    • typedef可以成为你的朋友,为一种类型引入新名字,而不是为变量分配内存
    • typedef int x[10]和#define x int[10]的区别
      • 可以用其他类型说明对宏类型名进行扩展
    #define peach int  
    unsigned peach i; /*没问题*/
    typedef int banana;
    unsigned banana i;/*错误,非法*/
      • 连续几个变量声明中,typedef保证所有变量为同一种类,#define定义则无法保证

    • typedef struct foo {..foo;}的含义,不同的命名空间内使用同一个名字,bad habit

    第4章 令人震惊的事实,数组和指针并不相同

    • 数组并非指针
    • 我的代码无法运行
    • /*file 1*/
      int mango [100];
      /*file 2*/
      extern int *mango;
    • 什么是声明,什么是定义
      • 声明,描述其他地方创建的对象
      • 定义,确定对象类型并为其分配内存,只能出现在一个地方
    • 使声明和定义匹配,指针的外部声明与数组不匹配,代码当然没办法运行
    • 指针和数组的区别
    指针 数组
    保存数据的地址 保存数据

    间接访问数据,首先取指针内容,把它作为地址,然后从这个地址取地址。如果指针有一个下标[I],就把指针的内容加上I作为地址,从中提取数据

    直接访问数据,a[I]只是简单的以a+I为地址取得数据
    通常用于动态数据结构 通常用于存储固定数目且数据类型相同的元素
    相关的函数为malloc().free() 隐式分配和删除
    通常指向匿名数据 自身即为数据名

    第5章 对链接的思考

    • 函数库、链接和载入

      C预处理器——>前端(语义和语法分析)——>后端(代码生成器)——>优化器——>汇编程序——>链接-载入器,编译器通常分割成几个更小的程序

      • 静态链接,函数库的一份拷贝是可执行文件的物理组成部分
      • 动态链接,可执行文件只包含了文件名,让载入器运行时自行寻找所需要的函数库
    • 动态链接的优点,体积小,共享数据库
    • 函数库链接的5个特殊秘密
      • 动态库文件扩展为“so”,静态为“a“
      • 通过-lthread选项,告诉编译器连接到libthread.so
      • 编译器期望在确定的目录找到库
      • 观察头文件,确认所使用的函数库
      • 与提取动态库中的符合相比,静态库中的符号提取的方法限制更严  
    • 警惕interpositioning,通过编写与库函数同名的函数来取代该库函数的行为
    • 产生链接器报告

    第6章 运动的诗章:运行时数据结构

    运行时数据结构包括栈,活动记录,数据和堆

    • a.out及其传说,assembler output,汇编程序和链接编辑输出格式
    • 段,segments,在unix中段表示一个二进制文件相关的内容块。文件中有三个段:文本段,数据段和BSS段
    • OS在a.out文件里干了些什么,可执行文件中段在内存如何分布(自己画一下内存中的分布图)
    • C语言运行时系统在a.out里干了些什么,C语言怎么组织正在运行的程序的数据结构(堆栈,活动记录,数据,堆等)

        堆栈段的三个主要作用:为局部变量提供存储空间,进行函数调用时存储与此相关的一些维护性信息,用作暂时存储区

    • 当函数被调用时发生了什么:过程活动记录(自己画过程活动记录的规范描述)
    • auto和static,函数内变量定义为static被保存在数据段而不是堆栈,就算退出函数,变量值依然保持。
    • 控制线程
    • setjmp和longjmp,主要用于错误恢复
    • UNIX中的堆栈段,当进程需要更多空间是,堆栈会自动生长
    • MS-DOS中的堆栈段,在可执行文件建立时,堆栈大小必须确定,不能再运行时增长
    • 有用的C语言工具:用于检查源代码的工具,用于检查可执行文件的工具,用于帮助调试的工具,性能优化辅助的工具

    2015年5月5日  星期二 9:43

    第7章 对内存的思考

    • Intel 80x86系列,向后兼容
    • Intel 80x86内存模型以及它的工作原理
      • 在UNIX中,段是一块以二进制形式出现的相关内容
      • 在内存模式中,段是内存模型设计的结果,一块64KB的内存区域
      • 在OS中,段与操作系统的内存管理有关
    • 虚拟内存,通过“页”形式组织,页是OS在disk和memory之间移动的单位,一般为几K字节
    • Cache存储器 ,全写法cache和写回法cache
    • 数据段和堆,像堆栈段能够根据需要自动增长一样,数据段也包含了一个对象,用于完成这项工作,这就是堆。堆用于动态分配的存储,通过malloc等库函数获得内存。
    • 内存泄露

        C语言通常不使用垃圾收集器,自动确认并回收不再使用的内存块。

        堆经常出现两种类型的错误:

      • 释放或改写仍在使用的内存
      • 未释放不再使用的内存 
    • 总线错误,总线错误大多是因为未对齐的读或写引起的,段错误是由于内存管理单元异常,通常由于解引用一个未初始化/非法值的指针引起

    第8章 为什么程序员无法分清万圣节和圣诞节

    看了之后有点不知所云,还是理解不够深,好零碎的感觉

    第9章 再论数组

    • 什么时候数组和指针相同?

        

    • 为什么会发生混淆
      • 作为函数的形式参数时,数组和指针可互换
      • 表达式中数组名(与声明不同)被compiler当做一个指向该数组第一个元素的指针
      • C语言把数组下表作为指针的偏移量
    • 为什么C语言把数组形参当做指针,传值调用,传址调用?
    • 数组片段的下标

        通过向函数传递一个指向数组任意元素的指针,这样传递给函数的就是从该元素之后的数组片段

    • 数组和指针可交换性的总结
      • 用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+i)这样的指针访问
      • 指针始终是指针,绝不可以改写为数组。你可以用下标形式访问指针,一般都是指针作为函数参数的时候,而且你知道实际传递给函数的是一个数组
      • 在特定的上下文中,也就是作为函数的参数,一个数组的声明可以被看成一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为一个指向数组第一个元素的指针
      • 因此,当把一个数组定义为函数参数时,可以选择把它定义为数组,也可以定义为指针。不管何种选择,在函数内部事实上获得的都是一个指针
      • 在其他情况中,定义和声明必须匹配。
    • C语言的多维数组
      • 尽管术语上称作多维数组,但C语言实际上只支持“数组的数组”
      • int apricot[2][3][4]在内存中的定位(可以自己画一下) 
      • 内存中数组如何布局:“行主序”,数组最右边下标最先变化 
      • 对多维数组的初始化

    第10章 再论指针

    • 多维数组的内存分布,以线性形式排列在内存中,array[i][j]——>*(*(array+i)+j)
    • 指针数组就是Iliffe向量,声明一个一维指针数组,每个指针指向一个字符串来取得类似于二维字符数组的效果.char *pea[4];char pine[4][5];
    • 在锯齿状数组上使用指针,字符串指针数组,右端长度不一
    • 向函数传递一个一维数组,需要长度约束,有两种方法
      • 增加额外参数表示元素数目,argc的作用
      • 赋予数组最后一个元素一个特殊的值,该值不会作为正常元素出现在数组中
    • 使用指针向函数传递一个多维数组
      /*二维或更多维数组无法在C语言中用作一般形式的参数*/
      my_function(int my_array[10][20]);
      my_function(int my_array[][20]);
      my_function(int (*my_array)[20]); my_function(
      char ** my_array); /*字符串指针*/

      对于多维数组作为参数传递的支持缺乏是C语言存在的一个内在限制。这使得用C语言编写某些特定类型的程序非常困难,如数值分析算法。

    • 使用指针从函数返回一个数组
      /*先声明函数*/
      int (*paf()) [20];
      /*定义函数*/
      int (*paf()) [20]{ 
          int (*pear)[20];  
          pear=calloc(20,sizeof(int)); 
          if(!pear)longjmp(error,1); 
          return pear; 
      }
      /*调用函数*/
      int (*result)[20];
      result=paf();
      (*result)[3]=12;
    • 使用指针创建和使用动态数组
      • 使用malloc()函数得到一个指向一大块内存的指针,然后像引用数组一样引用内存
      • realloc()对一个现在的内存块大小进行重新分配,同时不会丢失原来块的内容  

        

    第11章 你懂得C,所以C++不在话下

    • 初识OOP,面向对象编程:封装,继承,多态(动态绑定?)
    • 抽象——取事物的本质特性
      • 隐藏不相关细节
      • 向外界提供“黑盒子”接口
      • 把一个复杂的系统分解成几个相互独立的组成部分
      • 重用和共享代码
    • 封装——把相关的类型、数据和函数组合在一起
      • 类把代码和相关数据封装(捆绑)在一起
    • 展示一些类,类<-->对象,类型<-->变量
    • 访问控制,public,private,protected后面可以跟一大串声明,friend和virtual只能用于一条声明
    • 声明,正常的C语言声明,包括函数,类型或数据
    • 如何调用成员函数,点操作符.
    • 继承——复用已定义的操作
    • 多重继承
    • 重载,作用于不同类型的同一操作具有相同的名字
    • C++如何进行操作符重载
    • C++输入/输出,cout<<"the value is:"<<i<<endl;多个I/O操作数链接在一起
    • 多态——运行时绑定
      • 支持相关的对象具有不同的成员函数(但原型相同),并允许对象与适当的成员函数进行运行时绑定。virtual关键字告诉编译器该成员函数是多态的。
      • 多态是指一个函数或操作符只有一个名字,但它可以用于几个不同的派生类类型的能力    
    • 解释
      • 当相应派生类的成员函数取代基类的同类函数是,C++要求你必须提前通知compiler,方法就是在可能被取代的基类成员函数前加上virtual关键字
    • C++如何表现多态
      • vptr指针实现虚函数,vptr指针指向一个叫做vtbl的函数指针向量(称为虚函数表,也称为V表)。每个类都有这样一个向量,类中每个虚函数在该向量中都有一条记录
      • 具体可参看别人的一篇博客,对于虚函数在内存中分配等问题分析的非常透彻 http://blog.jobbole.com/86843/
    • C++的其他要点
      • 异常,在错误处理时改变程序的控制流
      • 模板,支持参数化类型 ,类和对象的关系<---->模板和函数的关系
        template<class T> 
        T min(T a,T b)
        {
            return (a>b)?a:b;
        }
      • 内联inline
      • new和delete操作符,new可以真正地建立一个对象,malloc()函数只分配内存。
      • 传引用调用,call-by-reference。  
  • 相关阅读:
    Java day 15
    Java day 14
    Java day 13
    Java day 12
    Java day 11
    Java day 10
    Java day 9
    Java day 8
    Java day 7
    Java day 6
  • 原文地址:https://www.cnblogs.com/sherPur/p/4555602.html
Copyright © 2011-2022 走看看