C Primer Plus读书笔记(二)

文章目录

本文是《C Primer Plus》第六章至第八章读书笔记,持续更新中。

ch06. C控制语句:循环

  1. C语言支持哪些循环控制关键字
  2. 循环体中(里)变量的作用域
  • 可以通过scanf函数控制循环 - 如果输入数据无法转换成指定类型的时候,scanf函数返回0

  • while循环部分要点:只有测试条件之后的单独语句(简单或者符合语句)才是循环部分 (一般编程习惯好的都不会出现这种情况,但是也得了解如果出现这种情况到底是因为什么。现代高级的IDE都会有相应的提醒)

    1int n = 0;
    2while (n < 3)
    3	printf("n is %d\n", n);
    4	n++;  // 这里的n++已经不是循环体的一部分了,这个程序会陷入死循环
    
    1int n = 0;
    2while (n++ < 3); // 这里的分号是一个完整的语句了,一个空语句,只有这个空语句是while的循环体,因此这个程序只会打印 - n is 4
    3	printf("n is %d\n", n)
    
  • 关系表达式 - 浮点数比较时尽量只使用><,因为浮点数的舍入误差会导致逻辑上应该相等的两个数不相等

TIP - 在构建是否相等的关系表示式的时候,如果是比较是否和一个常量相等,这时候可以把常量放左边,这可以避免误把赋值操作当做了比较操作

15 = canoes; // 语法错误,编译器不允许这么做
25 == canose; 
  • C语言中,数值可以作为测试表达式(真值),但是C语言的真值的逻辑是:所有非0都视为真,只有0被视为假

     1int n = 3;
     2while (n)
     3	printf("%2d is true. | ", n--);
     4printf("%2d is false.\n", n);
     5n = -3;
     6while (n)
     7	printf("%2d is true. | ", n++);
     8printf("%2d is false.\n", n);
     9
    10// Output:
    11// 3 is true. |  2 is true. |  1 is true. |  0 is false.
    12// -3 is true. | -2 is true. | -1 is true. |  0 is false.
    
  • C99之前,用int表示真/假值。C99之后引入了_Bool类型,该类型只能存储1(真)或0(假)。如果把非0的数值赋值给_Bool类型变量,改变量自动被设置成1

  • **关系运算符优先级:**关系运算符的优先级比算术运算符(包括+和-)比赋值运算符高 (优先级:C Primer Plus读书笔记(一) | Standing on the Shoulder of Giants (jonathanlin.top))

ch07. C控制语句:分支和跳转

  1. 支持分支、跳转的关键字有哪些
  2. 字符I/O函数getcharputchar有什么特别之处
  3. goto语句是否应该使用,应该注意哪些事项
  4. if...else的配对问题
  • ch = getchar() - 与scanf("%c", &ch)类似,读取下一个字符赋值给变量ch

    • getchar - 读取每个字符,包括空格、制表符和换行符
    • scanf - 读取数字时会跳过空格、制表符和换行符
  • putchar(ch) - 与printf("%c", ch)类似,打印一个字符

  • ctype.h系列字符函数 - 接受一个字符作为输入,如果该字符属于某个特殊的类型,则返回一个非零值(True),否则返回零值(False)。这些函数可以判断是否为字母、数字、空白字符等

  • C编译器是忽略缩进的,当出现多个if...else的时候,一定要注意它们之间的配对。配对的原则是:如果没有花括号,else和离它最近的if配对

  • 逻辑表达式(有逻辑运算符&& || !参与的表达式)的求值顺序是从左往右,一旦发现有使整个表达式为假的因素,立即停止求值

  • 范围测试,例如判断score是否在90和100之间

    • score >= 90 && score<=100 ✔️
    • 90 <= score <= 100 ❌ 由于<=的求值顺序是从左到右,因此这里会先计算90 <= score,而整个关系表达值的值要么是0(False)要么是1(True),都是小于100,因此整个表达式的结果是True
  • 条件运算符?: - expression1 ? expression2: expression3

    • 如果expression1的值为True,那么整个表达式的值为expression2
    • 如果expression1的值为False,那么整个表达式的值为expression3
  • switch...case...

    • switch括号表达式中的值应该是一个整数值(包括char
    • case标签必须是整数类型(包括char)的常量或者整数型常量表达式
    • 不能用变量作为case标签
    • 如果没有添加break,那么匹配到某个标签以及之后所有的case都会进行匹配判断
     1switch(整型表达式)
     2{
     3  case 常量1:
     4    语句;
     5    break;
     6  case 常量2:
     7    语句2;
     8    break;
     9  default:
    10    语句;
    11    break;
    12}
    
  • 尽量避免或者不使用goto

    1goto label;
    2...
    3label: statement;
    

    ch08. 字符输入/输出和输入验证

    1. 输入和输出跟缓冲区有什么关系?
    2. 有缓冲和无缓冲有什么区别?
    3. 是否可以手动刷新输入输出缓冲区?
  • 无缓冲区:当用户输入字符后立即重复打印该字符,这是无缓冲区

  • 有缓冲区:用户输入的字符被收集保存在一个被称为缓冲区(buffer)的临时存储区,按下Enter后打印,这是有缓冲区

  • 缓冲类型:

    • 完全缓冲I/O:当缓冲区满的时候才刷新缓冲区
    • 行缓冲I/O:出现换行符时刷新缓冲区
  • 文件和流

    • 文件:存储器中存储信息的区域,不同的操作系统存储信息方式不同,因此文件的底层表示形式也不一样。有的分块有的不分块,有的块大有的块小
    • 流:C程序处理的是流,而不是文件。流或者说数据流是对输入输出的映射,换句话说,输入转换成数据流,数据流映射到文件,输出也是类似,文件映射成数据流。这样上层就忽略了底层因为操作系统不同带来的差异
  • 文件结尾EOF

    • 可以用处理文件的方式来处理键盘输入(原因是C语言处理的都是流)
    • 以往判断文件结尾的一种方式是,在文件末尾放一个特殊字符ctrl+z标记文件结尾
    • 无论操作系统实际使用何种方法检测文件结尾,C语言中检测到文件末尾的时候,会返回一个特殊的值EOF注意,EOF是一个值,并不是一个字符
    • EOF的值不在char的值表示的范围内
    • 在终端中,UNIX风格的操作系统通过ctrl+d模拟EOF
  • stdin和stdout

    • C语言上层处理的是数据流,至于数据流的源头和目的地是哪,实际上对上层语言是透明的
    • stdin - 程序从stdin获取到的数据流,数据的来源可能是键盘输入,也可能是来自文件,程序本身不知道源头,只知道处理的是数据流。stdin默认来源是键盘输入,可以通过重定向使得数据来源于文件
    • stdout - 程序将数据流发送给stdout,数据流的去处对程序是透明的。数据流经由stdout,可能输出到显示设备,也可能保存到文件。默认是输出到显示设备
    • <>是重定向符号