跳到主要内容

《C程序设计语言》 读后感

阅读需 10 分钟

最开始我是不想研究C语言的,课过了就行,但是又对嵌入式有点兴趣,不熟练C语言不太好。更重要的是,我期中考试不及格,打击加心疼。

目前我的 C 语言课程已基本结课,感受颇深。

课本最后章节涉及了单链表,给新生打了数据结构的基础。而我这学期才学数据结构(C语言描述)的时候,实在看不懂是怎么写的,数据结构难道有特殊的操作?折腾了快半个学期,提前把C课本翻完,仔细读了指针和结构两章,茅塞顿开。困扰我的原来是 C 的语法,之后慢慢就会写了。对于数据结构,我目前的理解是,数据存放的方式、架构,它并不拘泥于编程语言。

期末需要自组自选题目写一个系统,文档模块分配等等方面都十分规范。最近越上课越想赞叹,新生的基础已经如此扎实,不过还好现在补不算太晚。

选了这门课是我赚了。此外悄悄给老师点个赞,很负责。

说正题,这本书我窥伺了挺久。这两天读完,极力推荐有一定基础的朋友读一波,完善和提高 C 语言技能。下面是我摘取的部分,我认为比较重要的内容:

  1. printf 函数永远不会自动换行

  2. 数据类型的取值范围取决于具体的机器

  3. 整数除法操作执行舍位,但如果某个算术运算符有一个浮点型操作数和一个整型操作数,则在开始运算之前整形操作数将会被转换为浮点型

  4. EOF(end of file 文件结束 )为符号常量,定义在头文件

    中,不同的系统定义的值不同,这正是标准符号常量能够增加程序可移植性的原因所在

  5. 统计行数等价于统计换行符的个数,\n

  6. 单引号中的字符表示一个整型值

  7. 函数原型中的参数名是可选的

  8. 传值调用,引用调用。在C语言中被调用函数不能直接修改主调函数中变量的值,而只能修改其私有的临时变量副本的值。必要时,调用者向被调函数提供待设置值的变量的地址,此地址是指向变量的指针,被调用函数需要将对应的参数声明为指针类型,通过它间接访问变量

  9. 数组参数。将数组名用作函数时,传递给函数的值是数组起始元素的位置或地址,它并不复制数组元素本身

  10. extern 语句显式声明外部变量或通过上下文隐式声明

  11. 在ANSI C 中为了同老版本的C语言程序兼容,将空参数表作为函数声明方式,若要声明空参数表,必须使用关键字 void 进行显式声明

  12. 定义表示创建变量或分配存储单元,而声明只说明变量性质,不分配存储单元

  13. 注释不允许嵌套

  14. 对象的类型决定该对象可取值的集合以及对该对象执行的操作

  15. 大小写有区别,推荐变量名小写,符号常量名大写

  16. 语言本身无法控制加载和汇编程序

  17. 各编译器可以根据硬件特性自主选择合适的类型长度

  18. ‘\0’ 表示值为0的字符,即空字符,用以强调某些表达式的字符属性

  19. 常量表达式在编译时求值,而不是运行时求值

  20. 双引号不是字符串的一部分,只用于限定字符串

  21. 标准库函数 strlen(s) 返回字符串参数 s 的长度,但长度不包括末尾的’\0’

  22. 字符常量 ‘x’ 是一个整数,其值是字母 x 在机器字符集中对应的数值(内部表示值),而只包含一个字符的字符串 “x” 是包含一个字符 ( 即字母 x ) 以及一个结束符 ‘\0’ 的字符数组

  23. 枚举常量是一个常量整型值的列表,enum 类型为建立常量值与名字之间的关联提供便利方式,常量值可以自动生成,并检查此类型的变量中存储的值是否为该枚举的有效值

  24. 多个相同类型的变量拆为多个声明语句会占用较多空间

  25. 默认情况,外部变量与静态变量将被初始化为 0,未经显式初始化的自动变量的值为未定义(即无效值)

  26. 关系表达式或逻辑表达式中,结果值为0或1. 自动转换把较窄的操作数转换为较宽的操作数,不丢失信息的转换,但那些可以导致信息丢失的表达式并不非法,只是编辑器会警告

  27. 头文件定义了一组与字符集无关的测试和转换函数

  28. C 语言没有指定 char 类型的变量是否带符号。C 语言的定义保证了机器的标准打印字符集中的字符不会是负值,所以在表达式中这些字符总是正值。但是存储在字符变量中的位模式随机而动,为了移植性,最好指定限定符

  29. “真”意味着”非0”

  30. 表达式中 float 类型的操作数不会自动转换为 double 类型

  31. 使用 float 类型主要为了在使用较大的数组时节省存储空间,或节省机器执行时间,double 类型算术运算非常费时

  32. 带符号与无符号值之间的比较运算是与机器相关的,取决于机器中不同整数类型的大小

  33. 可移植性的实现伪随机数发生器函数rand,初始化种子数的函数srand

  34. 任何代码的执行结果与求值顺序相关,都是不好的程序设计风格。表达式求值顺序由编译器决定,最佳的求值顺序同机器结构有很大关系

  35. else 在没有花括号时采用就近原则

  36. static 类型的函数仅对该函数声明所在的文件可见,static 类型的内部变量是一种只能在某个特定函数中使用但一直占据存储空间的变量

  37. register 声明告诉编译器它声明的变量在程序中使用频率较高,只适用于自动变量以及函数的形式参数

  38. 底层硬件环境的实际情况对寄存器变量的使用有一定的限制,寄存器变量的地址无法访问,不同的机器中,对寄存器变量的数目和类型的具体限制也是不同的

  39. 指针是一种保存变量地址的变量,能够存放一个地址的一组存储单元(通常为2或4个字节),只能指向某种特殊类型的对象即必须指向某种特定的数据类型(但指向void类型的指针可以存放指向任何类型的指针)

  40. 通常机器都有一系列连续编号或编址的存储单元,可以被单个操纵,也可以被连续成组的操纵

  41. & 用于取一个对象的地址,只能应用于内存中的对象(变量与数组元素),* 是间接寻址或间接引用,作用于指针时,将访问指针所指向的对象

  42. 数组名代表该数组最开始的一个元素的地址

  43. 0 永远不是有效的数据地址,返回 0 可用来表示发生了异常事件

  44. C 语言没有提供将整个字符串作为一个整体进行处理的运算符

  45. char arr[10] 相当于,声明了一个数组,该数组有10个元素,其中每个元素都是一个指向char类型对象的指针,并且没有对它们初始化,它们的初始化必须以显式的方式进行,比如静态初始化或代码初始化。而 char (arr)[10] 表明,这是一个指针,指向具有10个字符类型对象的一维数组

  46. 主函数 main 若带参,则有两个,第一个为 argc 用于参数计数,表示运行程序时命令行中参数的数目,第二个为 argv 用于参数向量,指向字符串数组的指针

  47. argv[argc]的值必须为一空指针

  48. 命令行参数

  49. 任何类型的指针都可以转换为 void * 类型,并且在将它转换回原来的类型时不会丢失信息

  50. 函数本身不是变量,但可以定义指向函数的指针, int (comp)(void , void ) 表明comp是一个指向函数的指针,如果是 int comp(void , void ) 表明 comp 是一个函数,该函数返回一个指向 int 类型的指针

  51. 复杂声明

  52. 结构是一个或多个变量的集合,将一组相关的变量看作一个单元

  53. 关键字 struct 引入结构声明

  54. 结构声明之后不带变量表,那么它仅仅描述了一个结构的模板或轮廓,不需要为它分配存储空间

  55. sizeof 用来计算任一对象的长度,返回一个等于指定对象或类型占用的存储空间字节数

  56. typedef 建立新的数据类型名,实际上是为某个已存在的类型增加了一个新的名称

  57. 联合,是在不同时刻保存不同类型和长度的对象的变量,编译器负责跟踪对象的长度和对齐要求。它提供了一种方式,以在单块存储区中管理不同类型的数据,而不需要在程序中嵌入任何同机器有关信息

  58. 使用类似于编译器符号表的单个二进制标志集合可以将多个对象保存在一个机器字中。外部强加的数据格式(如硬件设备接口)也经常需要从字的部分位中读取数据

  59. 位字段,可直接定义和访问一个字中的位字段的能力

  60. 大多数操作系统都限制了一个程序可以同时打开的文件数

  61. exit 函数被调用时将终止调用程序的执行。任何调用该程序的进程都可以获取 exit 的参数值。

  62. UNIX 操作系统通过一系列的系统调用(实际上是操作系统内的函数)提供服务

  63. 在 UNIX 系统内,所有的外围设备(包括键盘显示器)都被视为文件系统中的文件,所有的输入输出都要通过读文件或写文件完成

  64. 信息的表示仅出现在标准头文件中,使用它们的程序只需要在文件中包含这些头文件即可,不需要包含相应的声明

  65. 程序由存储在文件中的一个或多个翻译单元组成

再极力推荐对 C 语言有兴趣的朋友读读此书,书的价值远高于此。还有配套的习题解答。上述内容都是按照书页顺序摘抄的,部分有些改动扩充。如果有不明白的,看书通过上下文理解更有效。书不厚,精华却不少。

暂时未加入评论功能,请在对应公众号文章下或 GitHub Issues下留言反馈。