C Primer Plus读书笔记(二)
文章目录
本文是《C Primer Plus》第六章至第八章读书笔记,持续更新中。
ch06. C控制语句:循环
- C语言支持哪些循环控制关键字
- 循环体中(里)变量的作用域
可以通过
scanf
函数控制循环 - 如果输入数据无法转换成指定类型的时候,scanf
函数返回0while
循环部分要点:只有测试条件之后的单独语句(简单或者符合语句)才是循环部分 (一般编程习惯好的都不会出现这种情况,但是也得了解如果出现这种情况到底是因为什么。现代高级的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控制语句:分支和跳转
- 支持分支、跳转的关键字有哪些
- 字符I/O函数
getchar
和putchar
有什么特别之处goto
语句是否应该使用,应该注意哪些事项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. 字符输入/输出和输入验证
- 输入和输出跟缓冲区有什么关系?
- 有缓冲和无缓冲有什么区别?
- 是否可以手动刷新输入输出缓冲区?
无缓冲区:当用户输入字符后立即重复打印该字符,这是无缓冲区
有缓冲区:用户输入的字符被收集保存在一个被称为
缓冲区(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,可能输出到显示设备,也可能保存到文件。默认是输出到显示设备
<
和>
是重定向符号