step

C prime plus 查漏补缺

概述

由于之前学的是 CPP 没有系统的学过 C,日常则将二者混用,但用的时候总有些概念不清晰,所以重读了 《C Prime Plus》 总结并摘录了一些内容。

总结&摘录

  • 1972 年为了开发 unix 系统而设计了 C 语言,C 语言是在 B 语言的基础上发展而来,设计 C 语言的初衷是实用。
  • 自顶向下的规划,结构化编程和模块化设计使得 C 语言易懂可靠。
  • 结构紧凑,速度快。
  • 可移植性。
  • 强大且灵活,例如 unix 操作系统大都是 C 语言鞋的,大部分其他软件的编译器也是 C 语言写的。
  • C 语言比较自由,与此同时带来的的后果例如:指针灵活,排错不易。
  • C++ 是 C 的超集
  • 嵌入式开发领域
  • 操作系统
  • 流程:存储器 => 内存 => CPU
  • CPU 中有很多寄存器,这些寄存器处理的是指令。
  • 指令比较复杂冗余,侧重于实现细节。
  • 高级语言则精简,侧重于思维层面。
  • CPU 能够处理的是指令,从高级语言到指令是通过编译器来实现的。
  • C 语言发展初期并没有什么标准。
  • K&R C或经典C:1978 年出现第一版公认的标准 。
  • C89/C90 标准:于1989 年提出 ANSI C 标准,1990 年采用。通常称为 ANSI C 标准
  • C99 标准:在原有标准之上提供了新特性

    • 国际化编程,例如处理多种方法来处理国际字符集。
    • 解决明显缺陷:例如将 C 移至 64位处理器时出现的问题。
    • 提高 C 的适应性:适应科学工程项目中的关键数值计算。
  • C99 虽然发布很久,但是并非所有的编译器都适配。
  • C11 标准 2011 年发布,
  • 流程:定义程序 => 设计程序 => 编写代码 => 编译 => 运行程序 => 测试和调试程序 => 维护和修改程序
  • 定义程序:脑子里思考想法。
  • 设计程序:想法转换成代码,可以写出伪码。
  • 编写代码:实现代码并注意细节。
  • 编译:将源代码编译成机器语言。
  • 运行程序:直接运行,查看运行。
  • 测试和调试程序:输入数据,查看预期结果。
  • 维护和修改代码:调试发现代码不正确就修改代码重新运行。
  • 程序越大前两步越重要,初学者遇到的问题简单往往省略前两步。
  • 源代码:用编辑器写出来的代码,存放在文本文件中。文件以 .c 结尾的文件。例如 budget.c 其中 budget 是基本名,点号后面是扩展名。基本名 + 扩展名 = 文件名
  • 编译器:编译器是将源代码转换成中间代码的。
  • 链接器:将中间代码和涉及到的其他代码合并生成可执行文件。链接器是将目标代码 + 库代码 + 启动代码 三者合并到一起生成可执行代码。
  • 如果程序在屏幕中一闪而过,可以在 return 之前添加 getchar(); 这行代码会让程序等待击键,窗口会在用户按下下一个键后才关闭。
  • #include<stdio.h> 包含另外一个文件,也就是把 stdio.h 文件中的内容贴到这个位置。实际上是一种粘贴拷贝的意思。这个文件是 C 编译器软件包的标准部分,提供键盘输入和屏幕的输出支持,也就是 printf()scanf() 这两个函数的功能。
  • #include 是 c 的一条预处理指令,编译器在编译前会做一些准备工作,也就是预处理。头文件帮助编译器把程序正确的组合在一起。
  • int main(void) int 表示函数返回一个整数,圆括号表示 main 是函数名,void 则表示该函数不带任何参数。void 可以省略,为了确保兼容性较新的编译器最好带上。
  • 旧式 C 编译器允许这样写 int main()void main()甚至这样写 main() 但是 C99/C11 不允许,最好写成标准形式,这样从别的编译器移植到另外一个编译器上就不会出错。
  • /* */ 其中 /**/ 中间部分是可以写注释,多行注释。
  • C99 新增的单行注释 // 注释的目的是为了帮助读者理解程序,编译器会忽略注释
  • {} 函数体放在花括号中间。
  • int num 声明了一个名为 num 的变量并且这个变量是整数。 int 关键字,整型的数据类型。
  • 实参:传递给函数参数是实际的值
  • 形参:传递给函数参数是变量,变量中存储的是一个值。
  • \n 表示换行符,当前输出结束后,在下一行的左边重新开始。
  • 提高程序的可读性:(1) 有意义的变量名 (2) 写注释 (3) 使用空行来分隔概念上的多个部分 (4) 每条语句占一行。
  • 写函数时尽量提供函数原型。
  • printf() 向屏幕中输出时会先将内容输出到缓冲区中,至于缓冲区什么时候输送到屏幕之上有三种情况:1. 缓冲区慢 2. 遇到换行符 3. 需要输入时。
  • scanf 以空格来判断输入内容的结束。
  • 字符串为默认在结尾添加上 ‘\0’ 如果字符串长度为 1 也默认存在 ‘\0’ 例如 string x = a x 存入内存中的是 a\0 所以字符串默认以 \0 结尾。其中 \0 是空字符,ASCII 码值为 0
  • sizeof() 以字节为单位得到对象的大小。而 strlen() 则可以得到字符串中的字符长度。注意结尾的 \0 并不被 strlen 计入其中。
  • define 用来定义常量,const 用来限定一个只读的变量,也就是定义好了后就不能更改。
  • 考虑到影响执行的速度,C编译器不会检查数组的下标是否正确。例如长度 4 的数组 a, 令 a[10] = 1 编译器是检查不出来错误的,但是这个数据可能放在别的数据位置之上导致程序出错或者程序异常中断。
  • 模块化隐含的思想是:应该把程序划分为一些独立的单元,每个单元执行一个任务。这样做提高了程序的可读性。也许更重要的是,模块化使程序的不同部分彼此独立,方便后续更新或修改程序。在掌握如何使用函数后,可以把每个执行任务的单元放进函数中,提高程序的模块化。
  • The idea behind modularity is: the program should be divided into independent units,every unit only execute a task。这样做提高了程序的可读性。也许更重要的是,模块化使程序的不同部分彼此独立,方便后续更新或修改程序。在掌握如何使用函数后,可以把每个执行任务的单元放进函数中,提高程序的模块化。
  • getchar() / putchar() 只处理字符,所以速度比 scanf/printf 更快,更简洁。
  • getchar() / putchar() is only deal characters , so the speed is more than scanf/printf fast, and more concise. What’s more they don’t need conversion instructions.
  • 当向程序输入数据时,数据会不会直接进入程序中。而是先进入缓冲区,直到将所有数据输入完毕才进入程序。提交完整的一块数据会节约时间。同时根据输入方式缓冲区分为完全缓冲和行缓冲,也就是前者是直到所有数据输入完毕后缓冲区的数据才会进入程序中,后者是输入一行数据,缓冲区的数据就会进入内存中。
  • *和指针名之间的空格可有可无。通常,程序员在声明时使用空格,在解引用变量时省略空格。
  • & 运算符的作用是取地址 例如 int a = 24&a 则可以得到变量 a 的具体存储位置。
  • * 运算符的作用是提取出指针指向的地址中的变量内容。*a 这里的 a 指的是地址,加上 * 后表示提取这个地址中存储得变量。
  • 总结 & 是根据变量拿到地址。* 是根据地址拿到其中存储的变量。
  • const 声明变量后,变量内容不可更改。 例如 const int a = 1; a 的值不能够在修改。
  • int a[6] = {[5] = 212}; C99 标准允许这样写。
  • 数组名就是指针指向的数组下标为零时对应的地址。所以数组的本质就是指针,*(a + 10) = a[10]
  • 如果用数组来表示指针的话 *(a+1) 表示 a[1],而 *a + 1 表示 a[0] = a[0] + 1
  • 指针在声明的时候一定要初始化,如果不初始化的化为默认指向内存中的一个位置,这个位置本身可能存有值,也可能不存值,如果存有值,当使用指针的时候可能会将值给覆盖掉而导致程序崩溃。所以声明指针一定要初始化!
  • #include <cstdlib> 在这个库中有对应的伪随机数函数。直接调用 rand() 输出随机数,如果想要设置固定范围内的随机数, [a,b]rand()%b + a
  • ~ 按位取反, 0 => 1 1 => 0
  • & 按位与,一假即假,两真才真,也就是 1&1 = 11&0=0 0&1=0 0&0=0
  • 掩码 a = a & mask; 其中 mask 是掩码,通过按位与操作一假即假,可以理解成沙漏,将想要通过的位对应掩码设置为 1 ,不能通过的位置对应掩码设置为 0,这样筛选出来一个想要的值。至于掩码的如何设置可以根据生成出来的结果和原码想结合,反推出来掩码每一位的值,掩码就钥匙。
  • | 按位或,一真即真,两假才假,也就是 0|0 = 01|0=1 0|1=1 1|1=1 和按位与相反。
  • 当修改某一位的时候用到了 |
  • ^ 按位异或,无非四种情况,一真一假都为真,两真两假都为假 1^0 = 1 0^1 = 1 1^1=0 0^0=0
  • 在预处理开始钱,编译器会把多行物理行处理位一行逻辑行。
  • #include <stdlib.h> #include "name.h" 二者是有区别的,在 unix 系统下,采用尖括号包裹的文件,操作系统会直接选择去库中查找这个文件,而后者会先去当前目录中看看有没有这个文件然后再去库中查找。
  • floor(double x)ceil(double x) 分别是对 double 型变量进行向下取整和向上取整。
Tagged with c

Posted July 11, 2020


WIJE picweijiew . github