C语言程序设计_现代方法

182 阅读5分钟

第一章: C语言概述

  • 背景:
    • 人机交互单调
    • 用汇编写unix
    • 16k内存
  • 目的:
    • 替代汇编写unix,解决调试修改难和无法移植的问题
  • 特点:
    • 操作硬件,与unix系统集成
    • 语言小巧,编译器易于实现
    • 标准库功能强大
    • 类型和运算符丰富,表达力强
    • 很早形成标准,按统一规格开发的不同机型和OS版本的编译器,使C具备良好的可移植性

第二章: C语言基本概念

  • 编译过程

    • 预处理preprocessor:处理#开头的指令
    • 编译compiler:将源代码翻译成目标代码
    • 链接linker:将多个目标代码组装成一个可执行文件
  • 整数除法:C语言舍掉小数部分

    • 向下取整:5 / 10 = 0
    • 向上取整:(5 + 9) / 10 = 1。利用(操作数1 + 操作数2 - 1) / 操作数2 来实现向上取整,是一种编程技巧。
  • 初始化(initialize)

    • 编译器不会对所有变量自动赋初值。定义时赋初值,是一个好习惯。
    • 使用没有初始化(uninitialized)的变量是严重错误,程序可能崩溃。
  • 在任何需要数值的地方都可使用同类型的表达式

  • 预处理指令无分号,要求独立成行;其他语句有分号,可写到一行

  • 注释

    • 早期编译器会删除注释,a/**/b = 1变成ab=1,相当于给ab赋值;
    • 现代编译器根据C标准用一个空格替换注释,a/**/b = 1变成a b=1,就会报错。
  • 多项式求值:3x^5+2x^4-5x^3-x^2+7x^1-6

    • 常规方法: 3 * x * x * x * x * x + 2 * x * x * x * x - 5 * x * x * x - x * x + 7 * x - 6,执行14次乘法运算;
    • Homer方法: ((((3 * x + 2) * x - 5 ) * x -1) * x + 7) * x - 6,执行5次乘法运算,效率大幅提升;

第三章:格式化输入/输出

  • 转换说明 conversion specification
    • 也叫占位符,%开头,指示将位模式数值转换成何种形式的字符串
    • %5.3d显示40的时候,是| 040|
    • \" 将显示双引号 %%显示%
    • %i允许scanf以八进制(0开头)、十进制、十六进制(0x 0X开头)输入整数
  • scanf:

工作流程

  1. 到格式串里拿占位符,到输入流里提取子串
    • 提取第一个非空白字符放入子串,直到不能组成相应的数字为止;
  2. 匹配:int float string匹配规则不同
    • 匹配成功:(1)将子串转成值,保存到目标单元。(2)取下一个子串。
    • 匹配失败:结束并返回匹配成功的变量个数
  3. 格式串里的其他字符
    • 空白字符:如scanf("%d %d", &i, &j); 由于scanf读取第二个数字输入时跳过空白字符,在格式串中出现一个或多个空白字符对scanf无影响,在键盘输入的时候可以输入0个空格,也可以输入任意多个空格。
    • 其他字符:如scanf("%d,%d", &i, &j); 在两个%d之间设置输入分隔符逗号。从输入流里,读取第一个数后,碰到空格或者其他字符后结束读取,并将这个字符放回缓冲区原处,作为读取第二个数时的第一个字符。读第二个数字的时候,从输入流里拿出“放回原处”的字符,这个字符要和分隔符,比较,若两者不同,则scanf退出,若两者相同,则将此分隔符丢弃(不要读入第二个数字的字串里),继续向下读。

注意事项

  • 变量前漏掉&,程序可能崩溃
  • 专业程序员一般不用scanf读数据,采用字符格式读数据,再转换成数值形式

举例:scanf("%d%f", &i, &f); 输入 2-3.1e3

  • scanf拿出%d:到输入流跳过前2个空格,拿到2,继续读-,判断2-不是整数,子串确定为2,转成数值写到&i。然后记录-的位置,返回值+1;
  • scanf拿出%f:从-开始,float能用-开头,放入子串;接着,3.1e3经过同样判断并放入子串,读到空格判断不能作为float的一部分而停止,将字串-3.1e3转成数值并写到&f。然后再记录空格的位置,返回值+1;
  • scanf格式串处理结束,不再继续从输入流拿子串,将写入成功的变量个数返回,scanf结束。

问与答

  1. 转换说明%i和%d有什么区别?
  • 答:在scanf中,%d——十进制,%i——可处理十进制、八进制(0开头)、十六进制(0x 0X开头)三种输入。
  1. 如何显示%
  • 答:%%
  1. \t到底跳多远?
  • 答:由操作系统决定,或4个空格,或8个空格,和C无关。
  1. 如果要求读入一个数,而用户录入了非数值的输入,scanf如何处理?
  • 答:比如scanf("%d",&i); (1)如果输入23foo,scanf扫描到f后停止,将子串"23"转换成数值保存到&i处;(2)如果输入foo23,scanf扫描到f后停止,子串为空,无法给&i赋值。
  1. scanf如何把字符“放回原处”并在以后再次读取?
  • 答:键盘输入流在缓冲区里,scanf读到一个不符合当前占位符的输入时,将该字符放回缓冲区;scanf处理下一个占位符时,从这个“放回原处”的字符处开始读取。
  1. 用户在两个数之间输入了逗号,scanf如何处理?
  • 答:比如scanf("%d%d", &i, &j); 输入1,2, 将1读到&i,将逗号“放回原处”,读第二个数的时候,从逗号开始读,发现整数不能以逗号开头,读入错误scanf结束。
  1. 以下格式串是否等价?
  • scanf("%d-%d, &i, &j);只适应两种输入方式:
  • scanf("%d -%d, &i, &j);`可适应四种输入方式: