教材《C程序设计》第五版(谭浩强)第4章,书页 83–109,共 27 页|建议 2h
课前一句话
前三章的程序都是"一条道走到黑":从上往下,一句接一句,不用动脑子。这一课给程序装上眼睛——让它先看路牌,再决定走哪条路。学完这一课,你能亲手写出:判断闰年、成绩分档、解一元二次方程(含无实根、复根)、按距离算运费、四个数排序、判断点是否落在圆塔里。全章只有两个新句型:if 和 switch。别的都是给它们配的"路牌写法"。
一、先补地基:本章要解决的问题
先回忆第 3 章:你写的程序是这样的——
scanf("%f", &r);
s = 3.14159 * r * r;
printf("%f", s);不管输入什么,这三句都要依次执行。这叫顺序结构:无条件,不判断,一条直路。
可现实中到处是岔路口:
- 如果 x ≥ 0,输出 x;否则输出 −x。(求绝对值)
- 如果考试及格,放假;否则补考。
- 如果 b²−4ac ≥ 0,算实根;否则打印"无实根"。
这些事,顺序结构做不到——它不会"看情况"。
所以本章要解决的就一句话:让程序在岔路口先看路牌,再决定走哪条路。
整章我就用一个比喻贯穿到底:你开车,程序就是你,条件就是路牌。
| 现实里的开车 | C 语言里对应的东西 |
|---|---|
| 一条直路,没有岔口 | 顺序结构 |
| 前方 Y 形岔路,必须二选一 | if ... else ... |
| 路口只有一条匝道,可下可不下 | if (...) 单分支 |
| 岔路里还有岔路(匝道再分叉) | 嵌套 if |
| 高速上一连串出口,从第一个满足的出去 | if ... else if ... else if ... |
| 一排带编号的停车位,直接开到对应编号,进门后不刹车就一路开到下一个位 | switch ... case ... break |
| 路口立一块牌子,一句话说清走哪边 | 条件运算符 ? : |
C 语言的选择语句只有两种:if 语句(管两个分支)和 switch 语句(管多个分支)。其余全是这两位的变体。
本章没有带 * 的选学节,4.1–4.8 八个小节全部在考试范围内。
二、知识点讲解
4.1 选择结构和条件判断
一句话:选择结构,就是程序先算一个条件,根据结果是"真"还是"假",从两条(或多条)路里挑一条走。
拆名字:选择 = choose,结构 = structure;条件 = condition,判断 = judge。合起来:按条件挑一条路的结构。
生活比喻:导航开车到岔路口。路牌写着"上海 / 沈阳",你根据目的地选一条。选完就沿着这条路一直开,不会再回头走另一条。
怎么用:C 里靠 if 和 switch 实现。本章先讲 if 管双分支,再讲 switch 管多分支。
关键理解:if 后面括号里放的是一个表达式。C 不管这个表达式"长什么样",只看它算出来的值:
- 值非 0 → 当作"真",执行 if 后面的语句;
- 值等于 0 → 当作"假",跳过(有 else 就去 else)。
考点 if 括号里的表达式可以是关系表达式、逻辑表达式,甚至就是一个变量或一个数。书上原话:"可以是一个数值表达式"。
易错 很多同学以为 if 括号里只能写 a > b。写 if (x) 完全合法,意思是"x 不等于 0 就执行"。
4.2 用 if 语句实现选择结构
4.2.1 用 if 语句处理选择结构举例
书上用三个例子开路:例 4.1(解方程,判断有没有实根)、例 4.2(两个数排序)、例 4.3(三个数排序)。三个例子都围绕同一件事:先比较,再决定要不要交换 / 要不要输出。
这里先把例 4.2、4.3 里最值钱的那个动作讲透:交换两个变量的值。
生活比喻:两个杯子,A 杯装醋,B 杯装酱油,要互换。你不能直接把 A 倒进 B——B 里的酱油就没了。必须拿第三个空杯子 C:A→C,B→A,C→B。
代码三件套(考点,背下来):
t = a; /* 先把 a 存进临时杯 t */
a = b; /* 再把 b 倒进 a,此时 a 原来的值已在 t 里,不会丢 */
b = t; /* 最后把 t 里存的原 a 值倒进 b */易错 写成 a = b; b = a; 是错的:第一句执行完,a 已经变成 b 的值,第二句再把 b 赋给 b,两个变量都成了原来 b 的值,a 的原值永久丢失。
4.2.2 if 语句的一般形式
一句话:if 语句的完整形式是"如果……就……否则……",其中"否则"那一半可以不要。
拆名字:if 英文就是"如果";else 英文是"否则"(else = 别的、另外)。
一般形式(书上原文):
if (表达式) 语句1
[else 语句2]方括号表示可选:else 可有可无,语句 1、语句 2 都可以是简单语句、复合语句(花括号包起来的一坨),也可以是另一个 if。
三种常用形式(考点,考试让你"写出 if 的三种形式",照这个写):
| 形式 | 写法 | 走法 | 别称 |
|---|---|---|---|
| 1 | if (表达式) 语句1 | 条件真就做,假就跳过 | 单分支 |
| 2 | if (表达式) 语句1 else 语句2 | 二选一,必走其一 | 双分支 |
| 3 | if (表达式1) 语句1 else if (表达式2) 语句2 ... else 语句n | 从上往下挨个试,谁先真走谁 | 多分支(本质是嵌套) |
生活比喻:形式 1 是"前方有服务区,想进就进";形式 2 是"Y 形路口,必须选一条";形式 3 是"高速一连串出口,1 号出口没到就继续开,到了 2 号出口满足条件就出去,后面的出口就不再经过了"。
书上 6 条说明,我挑最要命的 4 条:
- 整个 if 可以写一行,也可以写多行;但提倡锯齿形缩进,否则自己都看不懂。
- 内嵌语句末尾必须有分号——分号是语句的一部分,不是 if 的。
- if 无论写几行,都是一个整体、一个语句。别看见分号就以为 if 结束了。
- 内嵌语句可以是复合语句,复合语句要用花括号括起来。
易错三大经典错误:
if (x > 0); /* 错:多了分号,if 管的是一个空语句 */
printf("正数"); /* 这句和 if 无关,永远执行 */
if (x > 0) y = 1 /* 错:y=1 后面少分号,编译报错 */
else y = -1;
else y = -1; /* 错:else 不能单独出现,它必须跟着 if */第 1 条特别阴:编译能过,结果全错。if 后面直接跟分号 = 条件白判断了。
4.3 关系运算符和关系表达式
4.3.1 关系运算符及其优先次序
一句话:关系运算符就是"比较大小"的六个符号,比较的结果只有"真"或"假"。
拆名字:relation(关系)+ al(形容词后缀)→ relational(关系的)。中文教材叫"关系运算",其实就是"比较运算"。
六个运算符(考点,必须背):
| 运算符 | 含义 | 优先级 |
|---|---|---|
< | 小于 | 高(前四个同级) |
<= | 小于或等于 | 高 |
> | 大于 | 高 |
>= | 大于或等于 | 高 |
== | 等于 | 低(后两个同级) |
!= | 不等于 | 低 |
三条优先级规则(书上原文):
- 前 4 个(
< <= > >=)同级,后 2 个(== !=)同级;前 4 个高于后 2 个。 - 关系运算符的优先级低于算术运算符。
- 关系运算符的优先级高于赋值运算符。
一句话记:算术 > 关系 > 赋值。
所以 c > a + b 等价于 c > (a + b);a = b > c 等价于 a = (b > c)。
易错 a > b == c 这种写法:因为 > 优先级高于 ==,等价于 (a > b) == c,不是 a > (b == c)。
4.3.2 关系表达式
一句话:用关系运算符把两个数值(或数值表达式)连起来的式子,叫关系表达式;它的值只有 1(真)或 0(假)。
生活比喻:两块路牌比大小。比完只给一个结论:"是"或"不是",不会给你一个数字。
怎么用:
5 > 3 /* 真,值为 1 */
5 == 3 /* 假,值为 0 */
a + b > b + c
(a = 3) > (b = 5) /* 合法:先赋值,再比较 */
'a' < 'b' /* 合法:比的是 ASCII 码 */
(a > b) > (b < c) /* 合法:拿两个 0/1 再比一次 */考点关系表达式的值参与运算时,真就是 1,假就是 0。
例:设 a=3, b=2, c=1,则 d = a > b 执行后 d 的值是 1;f = a > b > c 的值是 0——因为 > 是自左至右结合,先算 a > b 得 1,再算 1 > c 即 1 > 1,得 0。
易错把数学写法直接搬进 C:
if (0 < x < 10) /* 错!等价于 (0<x)<10,无论 x 多大都为真 */
if (x > 0 && x < 10) /* 对:两个条件都要写全 */易错== 写成 =(本章第一大坑):
if (a = 5) /* 这是赋值!a 被赋成 5,表达式的值也是 5,恒为真 */
if (a == 5) /* 这才是比较 */防错写法:把常量写左边,if (5 == a)。万一漏写一个等号,5 = a 会直接编译报错,错误当场暴露。
易错浮点数不要直接用 == 比较:0.1+0.2 在计算机里不等于 0.3(有微小误差)。正确写法:
if (fabs(a - b) < 1e-6) /* 差得足够小,就认为相等;fabs 要包含 math.h 头文件 */4.4 逻辑运算符和逻辑表达式
4.4.1 逻辑运算符及其优先次序
一句话:逻辑运算符用来把几个条件拼成一个复合条件——"并且""或者""不"。
拆名字:logic(逻辑)+ al → logical。中文叫"逻辑运算",大白话就是"组合条件"。
三个运算符(考点):
| 运算符 | 读法 | 含义 | 几目 |
|---|---|---|---|
&& | 逻辑与(AND) | 两边都真才真,有一个假就假 | 双目 |
|| | 逻辑或(OR) | 有一个真就真,两个都假才假 | 双目 |
! | 逻辑非(NOT) | 真变假,假变真 | 单目 |
生活比喻:
&&= 两道闸门串在一起,两道都开才通车("星期六 并且 不下雨,才去公园")。||= 两条路并联,任一条通就能走("年龄小于 12 或 大于 65,可以买优惠票")。!= 把路牌翻个面,"是"变"不是"。
优先级(考点,书上图 4.6):
!(最高) → 算术运算符 → 关系运算符 → && 和 || → 赋值运算符(最低)
注意两个细节:
!比算术还高!所以!a + b是(!a) + b。&&和||虽在同一档,但&&优先于||(书上原文:"!(非) → &&(与) → ||(或)")。
真值表(考点,背):
| a | b | a && b | a || b | !a |
|---|---|---|---|---|
| 真 | 真 | 真 | 真 | 假 |
| 真 | 假 | 假 | 真 | 假 |
| 假 | 真 | 假 | 真 | 真 |
| 假 | 假 | 假 | 假 | 真 |
4.4.2 逻辑表达式
一句话:用逻辑运算符把关系表达式(或其他逻辑量)连起来的式子,叫逻辑表达式;结果只有 1 或 0。
核心规则(必须分清两件事):
- 算出来的结果:只可能是 0 或 1。
- 拿来当操作数的东西:0 当假,任何非 0 都当真。
所以 4 && 2 的值是 1(不是 2,也不是 4);!4 的值是 0;!0 的值是 1。
考点短路求值(本章最值钱的考点,考试必考):
a && b && c:先看 a,a 为假就直接得 0,b、c 根本不算。a || b || c:先看 a,a 为真就直接得 1,b、c 根本不算。
书上那个经典例子,一定要会:
a = 1; b = 2; c = 3; d = 4; m = 1; n = 1;
(m = a > b) && (n = c > d);
/* 结果:m = 0,n 仍然是 1 */为什么 n 不变?因为 a > b 是 0,m 被赋成 0;&& 左边已经是假,右边 (n = c > d) 压根不执行,n 保持原值 1。
生活比喻:两道闸门串联,第一道关着,你根本不用跑去看第二道——反正过不去。
怎么用(闰年,本章必背表达式):
闰年条件:能被 4 整除且不能被 100 整除,或者能被 400 整除。
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
printf("%d is a leap year\n", year);反过来判非闰年,书上给了两种等价写法:
if (!((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0))易错把 && 写成 &、|| 写成 |:& 和 | 是位运算(本书后面才讲),虽然能编译,但含义完全不同,而且不会短路。
易错! 的作用范围:!a > b 是 (!a) > b,不是 !(a > b)。要否定一整个条件,必须加括号:!(a > b)。
4.5 条件运算符和条件表达式
一句话:? : 是 C 里唯一的三目运算符,能把一个简单的 if-else 压成一句话。
拆名字:条件运算符由 ? 和 : 两个符号组成,必须成对使用。三目 = 需要三个操作数(表达式1、表达式2、表达式3)。
生活比喻:路口立一块二选一的路牌:"前面堵车吗?走辅路 : 走主路"。看一眼,选一条,一句话说完。
一般形式:
表达式1 ? 表达式2 : 表达式3执行规则(考点):
- 先算表达式 1;
- 若为非 0(真),整个式子的值 = 表达式 2 的值,表达式 3 不计算;
- 若为 0(假),整个式子的值 = 表达式 3 的值,表达式 2 不计算。
所以它也是"短路"的,只算一条分支。
怎么用:
max = (a > b) ? a : b; /* 取两者较大值 */
ch = (ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch; /* 大写转小写 */
a > b ? printf("%d", a) : printf("%d", b); /* 当语句用 */优先级:条件运算符低于关系运算符和算术运算符,高于赋值运算符。所以 max = a > b ? a : b; 不用加括号也对(先算 a>b,再算 ?:,最后赋值)。
结合方向:自右至左(右结合)。所以可以嵌套:
max = (a > b) ? a : ((b > c) ? b : c); /* 三个数最大值 */易错 ?: 的两个分支类型最好一致;a > b ? a : b 里如果一个是 int 一个是 double,会发生隐式转换,初学阶段别玩这种。
考点 条件表达式可以出现在任何"表达式能出现"的地方;也可以单独成句(后面加分号),但初学阶段用得不多——书上原话"初学时用得不多"。
4.6 选择结构的嵌套
一句话:if 里面再套 if,就叫 if 的嵌套。
拆名字:nest 英文是"鸟巢",动词是"筑巢、嵌套"。大盒子装小盒子,就是嵌套。
生活比喻:岔路里还有岔路。先下高速(外层 if),下了匝道又分左右(内层 if)。
一般形式:
if (表达式1)
if (表达式2) 语句1
else 语句2
else
if (表达式3) 语句3
else 语句4考点悬空 else 问题(本章第二大坑):
规则只有一句:else 总是与它上面最近的、还没配对的 if 配对。
if (x > 0)
if (y > 0) printf("A");
else
printf("B");很多人看缩进以为 else 配外层 if,错。C 编译器不看缩进,只看距离:else 离内层 if (y > 0) 最近,所以配的是内层。实际含义是:
if (x > 0)
{
if (y > 0) printf("A");
else printf("B");
}怎么避免:书上给了三招——
- 让内层 if 也带 else,if 和 else 数量相等,从内到外一一对应;
- 用花括号把内层 if 括起来,明确"势力范围";
- 写代码一律锯齿形缩进(书上反复强调)。
易错 依赖缩进判断配对关系,是初学者最常见的读程序错误。考试给一段缩进很迷惑的代码问输出,就按"最近未配对"规则数。
4.7 用 switch 语句实现多分支选择结构
一句话:switch 根据一个整数(或字符)表达式的值,直接跳到对应标号处开始执行。
拆名字:switch 英文是"开关、切换"——像老式电灯的拉线开关,扳到哪一档,就接通哪一路。case 是"情况、案例",这里指"一种情况";default = de(加强)+ fault(缺失)→ "缺省、默认",即"以上情况都不是时";break 是"打断、跳出"。
生活比喻:一排带编号的停车位。你的车号是几,就直接开到几号位——不是从 1 号位挨个问过来。这就是 switch 和 if-else if 最大的区别:switch 是"直接跳",if 链是"挨个问"。
一般形式:
switch (表达式)
{
case 常量1: 语句1; break;
case 常量2: 语句2; break;
...
case 常量n: 语句n; break;
default: 语句n+1;
}书上 8 条说明,浓缩成 6 条必记:
- switch 括号里的表达式,值必须是整数类型(包括字符型)——不能是 float/double,不能是字符串。
case后面必须跟常量(或常量表达式),不能是变量,不能是范围。default可以没有;没有且所有 case 都不匹配时,switch 什么都不做,直接往下走。- 各 case 出现次序不影响结果,default 也可以写在最前面。
- 每个 case 的常量必须互不相同。
- case 只起"标号"作用,不在这里做条件检查。匹配到入口后,就一直往下执行,不再判断——除非遇到 break。
考点贯穿(fall-through):漏写 break,会从匹配的 case 一路往下执行,把后面所有 case 的语句全做一遍。书上例 4.6 若去掉全部 break,输入 A 会连续输出:
Your score:85~100
70~84
60~69
<60
enter data error!易错switch 里最容易错的四件事:
switch (score) /* 错:case 90 只匹配 90,85 没门 */
{
case 90: ... /* 想分段应该 switch (score / 10) */
}
case 1, 2: ... /* 错:多个 case 要写成 */
case 1: case 2: ... /* 这样,共用一组语句 */
switch (x) { case 1: int y = 0; } /* 错:C 里 case 标号后直接定义变量有坑 */
case 'A': printf("A"); /* 漏 break:会连带执行后面的 case */考点多个 case 共用一组语句的写法(书上例 4.10 用过):
case 2:
case 3: d = 5; break; /* c 等于 2 或 3,都执行 d=5 */4.8 选择结构程序综合举例
一句话:把 if、嵌套、switch、逻辑表达式混在一起,解决三个真实问题——闰年、一元二次方程、分段计费。
书上三个例子各有代表:
- 例 4.8 闰年:同一个问题给了 3 种写法(三层嵌套 if / else if 链 / 一个逻辑表达式)。这是"一题多解"的活教材,也是本章最可能考的程序。
- 例 4.9 一元二次方程:考"边界情况想全"——a=0 不是二次方程、disc=0、disc>0、disc<0 四种情况,一种都不能漏;还教你浮点数判等的正确姿势
fabs(disc) <= 1e-6。 - 例 4.10 运费:考"找规律"。折扣变化点都是 250 的倍数,于是令
c = s / 250,把 5 段折扣压成几个 case,用 switch 一次解决。
三个例子的完整代码和逐行解释,见下一节。
书末习题(书页 107–109)
本章书末共 12 题:第 1、2 题概念,第 3 题算逻辑表达式,第 4–6 题编程,第 7 题读程序找错,第 8–12 题编程。下一节逐题精讲,一题不漏。
三、现场写代码
例 4.1 解 ax²+bx+c=0(只处理实根)
题目:由键盘输入 a、b、c,值任意,不保证 b²−4ac≥0。若 ≥0 就算并输出两个实根,否则输出"此方程无实根"。
思路:先算判别式 disc = b²−4ac,用 if 分两路:disc<0 打印无实根;否则算 p=−b/2a、q=√disc/2a,x1=p+q、x2=p−q。
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, disc, x1, x2, p, q;
scanf("%lf%lf%lf", &a, &b, &c);
disc = b * b - 4 * a * c;
if (disc < 0)
printf("This equation hasn't real roots\n");
else
{
p = -b / (2.0 * a);
q = sqrt(disc) / (2.0 * a);
x1 = p + q;
x2 = p - q;
printf("real roots:\nx1=%7.2f\nx2=%7.2f\n", x1, x2);
}
return 0;
}逐行解释:
- 第 1–3 行:
stdio.h管输入输出,math.h管sqrt,main是程序入口。 - 第 4 行:全部用
double——书上的理由是提高精度、避免编译警告。 - 第 5 行:
%lf读双精度数,l是 long(长浮点型)。 - 第 6 行:先算判别式存进
disc,后面反复用,不重复计算。 - 第 7–8 行:
disc<0这一支,打印"无实根"。 - 第 9–10 行:
else后面有 6 条语句,是复合语句,必须用花括号括起来。 - 第 11–14 行:
p是两根中点,q是半距离,x1=p+q、x2=p-q。 - 第 15 行:
%7.2f= 总宽 7 位、保留两位小数。 - 第 16–17 行:复合语句结束,
return 0收尾。
运行结果(书上跑了两次):
6 3 1
This equation hasn't real roots2 4 1
real roots:
x1= -0.29
x2= -1.71易错 用 %f 读 double 会读错!scanf 读 double 必须用 %lf;printf 输出 double 用 %f 或 %lf 都行(printf 里 double 自动提升)。
例 4.2 两个实数按从小到大输出
题目:输入两个实数,按由小到大的顺序输出。 思路:比较一次;如果 a>b,就交换 a、b。交换必须借第三个变量 t。
#include <stdio.h>
int main()
{
float a, b, t;
scanf("%f,%f", &a, &b);
if (a > b)
{
t = a;
a = b;
b = t;
}
printf("%5.2f,%5.2f\n", a, b);
return 0;
}逐行解释:
- 第 1–3 行:头文件、入口、
float三个变量(t是交换用的"空杯子")。 - 第 4 行:格式串里有个逗号,输入时也要敲逗号,如
3.6,-3.2。 - 第 5–6 行:前大后小就进 if;交换三句是一个整体,用花括号括起来。
- 第 7–9 行:
t=a暂存,a=b覆盖,b=t还原——三只杯子法。 - 第 10–11 行:复合语句结束;此时 a 小 b 大,按序输出,
%5.2f宽 5 位两位小数。 - 第 12 行:结束。
运行结果:
3.6,-3.2
-3.20, 3.60例 4.3 三个数按从小到大输出
题目:输入 a、b、c,按由小到大输出。 思路(书上伪代码):S1 若 a>b 交换;S2 若 a>c 交换;S3 若 b>c 交换;S4 顺序输出。三次比较下来,a 最小、b 次小、c 最大。
#include <stdio.h>
int main()
{
float a, b, c, t;
scanf("%f,%f,%f", &a, &b, &c);
if (a > b)
{ t = a; a = b; b = t; }
if (a > c)
{ t = a; a = c; c = t; }
if (b > c)
{ t = b; b = c; c = t; }
printf("%5.2f,%5.2f,%5.2f\n", a, b, c);
return 0;
}逐行解释:
- 第 1–3 行:头文件、入口、三个数 + 一个临时杯。
- 第 4 行:三个数之间用逗号隔开输入。
- 第 5–7 行:三次交换——先保证 a≤b,再保证 a≤c(此时 a 已是三者最小),最后保证 b≤c。
- 第 8–10 行:此时整体有序,按序输出后结束。
运行结果(输入 3,7,1):
3,7,1
1.00, 3.00, 7.00例 4.4 大写字母转小写(条件运算符)
题目:输入一个字符,是大写字母就转成小写,不是就不转,最后输出。 思路:用条件表达式,一句话完成"判断 + 二选一"。
#include <stdio.h>
int main()
{
char ch;
scanf("%c", &ch);
ch = (ch >= 'A' && ch <= 'Z') ? (ch + 32) : ch;
printf("%c\n", ch);
return 0;
}逐行解释:
- 第 1–4 行:头文件、入口、字符变量、读一个字符(空格和回车也会被读进来)。
- 第 5 行:条件表达式——
ch>='A' && ch<='Z'判断大写;是就取ch+32(ASCII 里小写比大写大 32),不是就取原值。 - 第 6–7 行:按字符输出,结束。
运行结果:
A
a例 4.5 阶跃函数(嵌套 if 的两种写法)
题目:y = −1 (x<0),y = 0 (x=0),y = 1 (x>0)。输入 x,输出 y。 思路:三个值,必须用嵌套 if。书上给两种写法,第二种故意把 if 写在外层——正是"悬空 else"的实战。
程序 1(推荐写法:内层 if 放在外层 else 里):
#include <stdio.h>
int main()
{
int x, y;
scanf("%d", &x);
if (x < 0)
y = -1;
else if (x == 0)
y = 0;
else
y = 1;
printf("x=%d,y=%d\n", x, y);
return 0;
}逐行解释:
- 第 1–4 行:头文件、入口、两个整型变量、读入 x。
- 第 5–10 行:三岔口——x<0 取 −1;x==0 取 0;剩下的必是 x>0,取 1。注意这里用的是
==。 - 第 11–12 行:输出 x、y,结束。
程序 2(书上"注意分析此 if 语句"的写法):
#include <stdio.h>
int main()
{
int x, y;
scanf("%d", &x);
if (x >= 0)
if (x > 0) y = 1;
else y = 0;
else
y = -1;
printf("x=%d,y=%d\n", x, y);
return 0;
}逐行解释:
- 第 1–4 行:同程序 1,读入 x。
- 第 5–6 行:外层
if (x >= 0);内层if (x > 0) y = 1;。 - 第 7 行:这个 else 配的是内层 if(最近的未配对 if),处理 x==0。
- 第 8 行:这个 else 配的是外层 if,处理 x<0。
- 第 9–10 行:输出,结束。
运行结果:输入 -5 输出 x=-5,y=-1;输入 5 输出 x=5,y=1。
例 4.6 按成绩等级输出分数段(switch 入门)
题目:A 等 85 分以上,B 等 70~84,C 等 60~69,D 等 60 以下。等级由键盘输入。
#include <stdio.h>
int main()
{
char grade;
scanf("%c", &grade);
printf("Your score:");
switch (grade)
{
case 'A': printf("85~100\n"); break;
case 'B': printf("70~84\n"); break;
case 'C': printf("60~69\n"); break;
case 'D': printf("<60\n"); break;
default: printf("enter data error!\n");
}
return 0;
}逐行解释:
- 第 1–5 行:头文件、入口、字符变量、读字符、打印提示前缀(不换行)。
- 第 6 行:
switch (grade)——看 grade 是哪个"车位号"。 - 第 7–9 行:每个 case 匹配一种等级,打印分数段后立即 break 跳出。
- 第 10–11 行:
default兜底(比如输入 E 或小写 a),打印错误提示;它是最后一句,可不加 break。 - 第 12 行:结束。
运行结果:
A
Your score:85~100例 4.7 用 switch 处理菜单命令
题目:输入 'A'/'a' 执行 A 操作,输入 'B'/'b' 执行 B 操作,其他字符报警。 说明:书上原版把两个操作写成 action1、action2 两个函数(第 7 章才讲)。这里换成 printf 的等价版本,先专注 switch 的"多个 case 共用一组语句"。
#include <stdio.h>
int main()
{
char ch;
int a = 15, b = 23;
ch = getchar();
switch (ch)
{
case 'a':
case 'A': printf("x+y=%d\n", a + b); break;
case 'b':
case 'B': printf("x*y=%d\n", a * b); break;
default: putchar('\a');
}
return 0;
}逐行解释:
- 第 1–5 行:头文件、入口、命令字符 ch、两个操作数 a=15、b=23,
getchar()读一个字符。 - 第 6 行:
switch (ch)按命令字符跳转。 - 第 7–9 行:
case 'a':空着不写语句,直接落到case 'A':——两个 case 共用一组语句;'b'/'B' 同理。 - 第 10–11 行:
default用putchar('\a')响铃警告(\a是响铃符),结束。
例 4.8 判断闰年(一题三解)
题目:判断某一年是否为闰年。 思路:闰年 = 能被 4 整除且不能被 100 整除,或能被 400 整除。
程序 1(三层嵌套 if,书上原版):
#include <stdio.h>
int main()
{
int year, leap;
printf("enter year:");
scanf("%d", &year);
if (year % 4 == 0)
{
if (year % 100 == 0)
{
if (year % 400 == 0)
leap = 1;
else
leap = 0;
}
else
leap = 1;
}
else
leap = 0;
if (leap)
printf("%d is ", year);
else
printf("%d is not ", year);
printf("a leap year.\n");
return 0;
}逐行解释:
- 第 1–5 行:头文件、入口、
year存年份、leap是"标志变量"(1 闰年 / 0 非闰年),提示并读入。 - 第 6–15 行:三层嵌套——能被 4 整除?能被 100 整除?能被 400 整除?只有"能被 4 整除且不能被 100 整除"或"能被 400 整除"才 leap=1。
- 第 16–19 行:
if (leap)等价于if (leap != 0),按标志打印 "xxxx is " 或 "xxxx is not "。 - 第 20 行:补上 "a leap year.";这句在 if-else 外面,两种情况都会执行。
- 第 21 行:结束。
程序 2(else if 链,书上改法):
if (year % 4 != 0)
leap = 0;
else if (year % 100 != 0)
leap = 1;
else if (year % 400 != 0)
leap = 0;
else
leap = 1;程序 3(一个逻辑表达式,最简洁):
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
leap = 1;
else
leap = 0;运行结果:输入 2012 输出 2012 is a leap year.;输入 2100 输出 2100 is not a leap year.
例 4.9 一元二次方程(四种情况全覆盖)
题目:求 ax²+bx+c=0 的解。要考虑:a=0 不是二次方程;disc=0 两个相等实根;disc>0 两个不等实根;disc<0 两个共轭复根。
#include <stdio.h>
#include <math.h>
int main()
{
double a, b, c, disc, x1, x2, realpart, imagpart;
scanf("%lf,%lf,%lf", &a, &b, &c);
printf("The equation ");
if (fabs(a) <= 1e-6)
printf("is not a quadratic\n");
else
{
disc = b * b - 4 * a * c;
if (fabs(disc) <= 1e-6)
printf("has two equal roots:%8.4f\n", -b / (2 * a));
else if (disc > 1e-6)
{
x1 = (-b + sqrt(disc)) / (2 * a);
x2 = (-b - sqrt(disc)) / (2 * a);
printf("has distinct real roots:%8.4f and %8.4f\n", x1, x2);
}
else
{
realpart = -b / (2 * a);
imagpart = sqrt(-disc) / (2 * a);
printf("has complex roots:\n");
printf("%8.4f+%8.4fi\n", realpart, imagpart);
printf("%8.4f-%8.4fi\n", realpart, imagpart);
}
}
return 0;
}逐行解释:
- 第 1–5 行:头文件(
math.h提供fabs、sqrt)、入口、变量、逗号分隔读入(如1,2,1)。 - 第 6 行:先输出半句 "The equation ",不换行。
- 第 7–9 行:
fabs(a)<=1e-6判断 a 是否近似为 0——不能写a==0;是则不是二次方程。 - 第 10 行:算判别式 disc。
- 第 11–12 行:disc 近似为 0 → 两个相等实根。
- 第 13–15 行:disc 明显大于 0 → 两个不等实根,
%8.4f共 8 位、4 位小数。 - 第 16–19 行:剩下 disc<0 → 实部
-b/(2a)、虚部sqrt(-disc)/(2a)(注意里面是 −disc),再打印 p+qi 和 p−qi。 - 第 20 行:结束。
运行结果(书上跑三次):1,2,1 → two equal roots: -1.0000;1,2,2 → 两个复根 -1.0000+1.0000i / -1.0000-1.0000i;2,6,1 → distinct real roots: -0.1771 and -2.8229。
例 4.10 按距离计算运费(switch 找规律)
题目:s<250 无折扣;250≤s<500 打 2%;500≤s<1000 打 5%;1000≤s<2000 打 8%;2000≤s<3000 打 10%;s≥3000 打 15%。公式 f = p×w×s×(1−d/100)。
思路:折扣变化点都是 250 的倍数,令 c = s/250(整数除法),c=0 是 250 以下,c=1 是 250~500,c=2,3 是 500~1000,c=4~7 是 1000~2000,c=8~11 是 2000~3000,c≥12 是 3000 以上。
#include <stdio.h>
int main()
{
int c, s;
float p, w, d, f;
printf("please enter price,weight,distance:");
scanf("%f,%f,%d", &p, &w, &s);
if (s >= 3000)
c = 12;
else
c = s / 250;
switch (c)
{
case 0: d = 0; break;
case 1: d = 2; break;
case 2:
case 3: d = 5; break;
case 4:
case 5:
case 6:
case 7: d = 8; break;
case 8:
case 9:
case 10:
case 11: d = 10; break;
default: d = 15;
}
f = p * w * s * (1 - d / 100);
printf("freight=%10.2f\n", f);
return 0;
}逐行解释:
- 第 1–5 行:头文件、入口、整型 c 和 s、浮点 p/w/d/f、打印提示。
- 第 6 行:注意第三个是
%d(int),前两个是%f。 - 第 7–8 行:3000 以上统一令 c=12(一个 case 就够了);否则
c = s/250,整数除法自动取整,把距离映射成折扣除数。 - 第 9–14 行:switch 按 c 跳转;
case 2:空着落到case 3:,表示 2 和 3 共用 d=5;4~7 共用 d=8,8~11 共用 d=10;default处理 c=12,d=15。 - 第 15–17 行:套公式 f=p×w×s×(1−d/100),
%10.2f宽 10 位两位小数,结束。
运行结果:100,20,300 → freight= 588000.00。
四、书上习题精讲
第 1 题 什么是算术运算?什么是关系运算?什么是逻辑运算?
答:
- 算术运算:对数值做加减乘除求余(
+ - * / %),运算对象是数,结果还是数。 - 关系运算:对两个值做比较(
< <= > >= == !=),结果是"真"或"假"(C 里用 1 / 0 表示)。 - 逻辑运算:对逻辑量做与、或、非(
&& || !),结果也是"真"或"假"。
一句话区分:算术运算算"多少",关系运算比"大小",逻辑运算拼"条件"。
第 2 题 C 语言中如何表示"真"和"假"?系统如何判断一个量的"真"和"假"?
答:
- 表示:1 代表真,0 代表假。逻辑运算和关系运算的结果只可能是 1 或 0。
- 判断:系统判断一个量时,0 为假,非 0 为真。所以
if (x)里 x=5、x=−3、x=0.1 都算真,x=0 才算假。
注意这两句话不矛盾:"产生的结果"只能是 0/1,"判断的对象"可以是非 0 的任何值。
第 3 题 写出下面各逻辑表达式的值(设 a=3, b=4, c=5)
| 小题 | 表达式 | 计算过程 | 值 |
|---|---|---|---|
| (1) | a+b>c && b==c | 3+4=7>5 得 1;4==5 得 0;1&&0 | 0 |
| (2) | a || b+c && b-c | 先算 b+c=9、b-c=-1;&& 优先于 ||:9&&−1 得 1;3||1 | 1 |
| (3) | !(a>b) && !c || 1 | a>b=1,!1=0;!c=!5=0;0&&0=0;0||1 | 1 |
| (4) | !(x=a) && (y=b) && 0 | x=a 得 3,!3=0;&& 短路,后面不算 | 0 |
| (5) | !(a+b)+c-1 && b+c/2 | !(7)=0;0+5−1=4;c/2=2(整数除法),b+2=6;4&&6 | 1 |
考点 第 (2) 题考优先级,第 (4) 题考短路,第 (5) 题考整数除法——三个坑一题一个。
第 4 题 输入 3 个整数,输出其中最大的数
思路:先假定第一个是最大值,再拿后两个依次挑战它。
#include <stdio.h>
int main()
{
int a, b, c, max;
scanf("%d%d%d", &a, &b, &c);
max = a;
if (b > max) max = b;
if (c > max) max = c;
printf("max=%d\n", max);
return 0;
}解析:两个独立的 if(不是 else if)——因为 b、c 都要和当前最大值比。也可以写成 if (a>b) ... else ... 的嵌套版,但"打擂台"写法最不容易错。
第 5 题 输入小于 1000 的正数,输出其平方根(不是整数则取整数部分);先检查输入是否合法
思路:先判断 x > 0 && x < 1000,合法才 sqrt,否则提示错误。题目还要求"重新输入",那需要循环——第 5 章才学,这里给出两个版本。
版本 1(本章能写:只检查一次):
#include <stdio.h>
#include <math.h>
int main()
{
double x;
printf("enter a positive number less than 1000:");
scanf("%lf", &x);
if (x > 0 && x < 1000)
printf("%d\n", (int)sqrt(x));
else
printf("input error!\n");
return 0;
}解析:
x > 0 && x < 1000不能写成0 < x < 1000(恒真)。(int)sqrt(x)把 double 强制转成 int,小数部分直接截掉,正好满足"取整数部分"。- 负数和 0 都算非法,所以是
x > 0而不是x >= 0。
版本 2(预习第 5 章:用 do-while 反复要求重新输入):
#include <stdio.h>
#include <math.h>
int main()
{
double x;
do
{
printf("enter a positive number less than 1000:");
scanf("%lf", &x);
} while (x <= 0 || x >= 1000);
printf("%d\n", (int)sqrt(x));
return 0;
}解析:do-while 是"先做一次,再判断要不要重做",正好符合"输入—检查—不合法就重来"。这里只要看懂结构,第 5 章会细讲。
第 6 题 分段函数求值
题目:y = x (x<1);y = 2x−1 (1≤x<10);y = 3x−11 (x≥10)。
#include <stdio.h>
int main()
{
float x, y;
scanf("%f", &x);
if (x < 1)
y = x;
else if (x < 10)
y = 2 * x - 1;
else
y = 3 * x - 11;
printf("x=%.2f,y=%.2f\n", x, y);
return 0;
}解析:第二个条件只写 x < 10 就够了——能走到这一支,说明前面 x < 1 已经不成立,即 x≥1 自动满足。这就是 else if 链的"前面已排除"效应,不要傻乎乎写成 x >= 1 && x < 10(虽然也对,但啰嗦)。
第 7 题 分析两个程序能否实现阶跃函数
题目:给两个程序(书页 108),先分析逻辑、画流程图,再上机验证。函数同例 4.5。
程序(1):
int x, y;
printf("enter x:");
scanf("%d", &x);
y = -1;
if (x != 0)
if (x > 0)
y = 1;
else
y = 0;
printf("x=%d,y=%d\n", x, y);分析:else 与最近的未配对 if(即 if (x>0))配对,所以逻辑是:
- x≠0 时:若 x>0 → y=1;否则(x<0)→ y=0(错!应该 y=−1)
- x=0 时:外层条件不成立,y 保持 −1(错!应该 y=0)
| 输入 | 正确答案 | 程序输出 | 对错 |
|---|---|---|---|
| x=5 | 1 | 1 | 对 |
| x=0 | 0 | −1 | 错 |
| x=−5 | −1 | 0 | 错 |
结论:不能实现。错在 else 配错了对象。
程序(2):
int x, y;
printf("enter x:");
scanf("%d", &x);
y = 0;
if (x >= 0)
if (x > 0) y = 1;
else y = -1;
printf("x=%d,y=%d\n", x, y);分析:else 配内层 if。
- x≥0 时:x>0 → 1;x=0 → −1(错,应 0)
- x<0 时:外层不成立,y 保持 0(错,应 −1)
| 输入 | 正确答案 | 程序输出 | 对错 |
|---|---|---|---|
| x=5 | 1 | 1 | 对 |
| x=0 | 0 | −1 | 错 |
| x=−5 | −1 | 0 | 错 |
结论:也不能实现。两个程序都只对 x>0 正确。
正确写法见例 4.5 程序 1(把内层 if 放进外层 else 里,或老老实实写 else if 链)。
第 8 题 百分制成绩转等级 A~E
题目:90 以上 A,80~89 B,70~79 C,60~69 D,60 以下 E。
写法 1(else if 链):
#include <stdio.h>
int main()
{
int score;
scanf("%d", &score);
if (score >= 90)
printf("A\n");
else if (score >= 80)
printf("B\n");
else if (score >= 70)
printf("C\n");
else if (score >= 60)
printf("D\n");
else
printf("E\n");
return 0;
}写法 2(switch):
switch (score / 10)
{
case 10:
case 9: printf("A\n"); break;
case 8: printf("B\n"); break;
case 7: printf("C\n"); break;
case 6: printf("D\n"); break;
default: printf("E\n");
}解析:score/10 把百分制压成 0~10 的整数,正好能当 switch 的入口。注意 100 分时 score/10 = 10,必须把 case 10 和 case 9 并列,否则满分会被判成 E。这是本题唯一的坑。
第 9 题 不多于 5 位的正整数:求位数、逐位输出、逆序输出
思路:先用 if 链定位数(存进 place),再用 / 和 % 拆出每一位,最后用 switch 按位数输出。
#include <stdio.h>
int main()
{
int num, place, d5, d4, d3, d2, d1;
scanf("%d", &num);
if (num > 9999) place = 5;
else if (num > 999) place = 4;
else if (num > 99) place = 3;
else if (num > 9) place = 2;
else place = 1;
d5 = num / 10000;
d4 = num / 1000 % 10;
d3 = num / 100 % 10;
d2 = num / 10 % 10;
d1 = num % 10;
printf("place=%d\n", place);
switch (place)
{
case 5: printf("%d %d %d %d %d\n", d5, d4, d3, d2, d1); break;
case 4: printf("%d %d %d %d\n", d4, d3, d2, d1); break;
case 3: printf("%d %d %d\n", d3, d2, d1); break;
case 2: printf("%d %d\n", d2, d1); break;
case 1: printf("%d\n", d1); break;
}
printf("reverse=");
switch (place)
{
case 5: printf("%d%d%d%d%d\n", d1, d2, d3, d4, d5); break;
case 4: printf("%d%d%d%d\n", d1, d2, d3, d4); break;
case 3: printf("%d%d%d\n", d1, d2, d3); break;
case 2: printf("%d%d\n", d1, d2); break;
case 1: printf("%d\n", d1); break;
}
return 0;
}解析:
- 定位数用
>从大到小问:num>9999就是 5 位,num>999就是 4 位……顺序不能乱,否则 12345 会被判成 4 位。 num/1000%10的意思是"先去掉后三位,再取个位",即千位。这是拆数字的通用套路。- 两个 switch 一个正序、一个逆序,正好各用一次。
运行结果(输入 321):place=3 → 3 2 1 → reverse=123。
第 10 题 按利润提成算奖金
题目:I≤10 万提 10%;10 万<I≤20 万,超出 10 万部分提 7.5%;20 万<I≤40 万,超出 20 万部分提 5%;40 万<I≤60 万,超出 40 万部分提 3%;60 万<I≤100 万,超出 60 万部分提 1.5%;I>100 万,超出 100 万部分提 1%。
思路:分段累加。先算好各段"封顶奖金":10 万 → 1 万;20 万 → 1.75 万;40 万 → 2.75 万;60 万 → 3.35 万;100 万 → 3.95 万。
(1)用 if 语句:
#include <stdio.h>
int main()
{
double i, bonus;
scanf("%lf", &i);
if (i <= 100000)
bonus = i * 0.1;
else if (i <= 200000)
bonus = 10000 + (i - 100000) * 0.075;
else if (i <= 400000)
bonus = 17500 + (i - 200000) * 0.05;
else if (i <= 600000)
bonus = 27500 + (i - 400000) * 0.03;
else if (i <= 1000000)
bonus = 33500 + (i - 600000) * 0.015;
else
bonus = 39500 + (i - 1000000) * 0.01;
printf("bonus=%10.2f\n", bonus);
return 0;
}(2)用 switch 语句:
#include <stdio.h>
int main()
{
double i, bonus;
int c;
scanf("%lf", &i);
c = (int)(i / 100000);
switch (c)
{
case 0:
bonus = i * 0.1; break;
case 1:
bonus = 10000 + (i - 100000) * 0.075; break;
case 2:
case 3:
bonus = 17500 + (i - 200000) * 0.05; break;
case 4:
case 5:
bonus = 27500 + (i - 400000) * 0.03; break;
case 6:
case 7:
case 8:
case 9:
bonus = 33500 + (i - 600000) * 0.015; break;
default:
bonus = 39500 + (i - 1000000) * 0.01;
}
printf("bonus=%10.2f\n", bonus);
return 0;
}解析:10000 / 17500 / 27500 / 33500 / 39500 就是"前面各段封顶奖金",思路里已经算好,直接当常数用,代码短很多。(int)(i/100000) 把利润压成"十万"为单位,边界刚好对:i=100000 → 1(与 if 版 i<=100000 结果相同);i=200000 → 2;i=1000000 → 10,走 default。每个 case 的边界都要验一遍,这是分段题最容易翻车的地方。
第 11 题 输入 4 个整数,按从小到大输出
思路:和例 4.3 一样,但比较次数从 3 次变成 6 次:a 依次和 b、c、d 比,b 和 c、d 比,c 和 d 比。这叫"选择排序"的雏形。
#include <stdio.h>
int main()
{
int a, b, c, d, t;
scanf("%d%d%d%d", &a, &b, &c, &d);
if (a > b) { t = a; a = b; b = t; }
if (a > c) { t = a; a = c; c = t; }
if (a > d) { t = a; a = d; d = t; }
if (b > c) { t = b; b = c; c = t; }
if (b > d) { t = b; b = d; d = t; }
if (c > d) { t = c; c = d; d = t; }
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}解析:前 3 个 if 把最小的换到 a;中间 2 个把次小的换到 b;最后 1 个把 c、d 排好。6 次比较一次不多一次不少——这是 4 个数排序的最少比较次数。
第 12 题 圆塔高度
题目:4 个圆塔,圆心 (2,2)、(−2,2)、(−2,−2)、(2,−2),半径 1,高 10 m,塔外高度为 0。输入任一点坐标,求该点建筑高度。
思路:点到圆心的距离 ≤ 半径,就在圆内。用"平方比较"避免开方:(x−cx)²+(y−cy)² ≤ 1。四个圆心共用一套公式,用 || 连起来。
#include <stdio.h>
int main()
{
double x, y;
printf("enter x,y:");
scanf("%lf,%lf", &x, &y);
if ((x - 2) * (x - 2) + (y - 2) * (y - 2) <= 1
|| (x + 2) * (x + 2) + (y - 2) * (y - 2) <= 1
|| (x + 2) * (x + 2) + (y + 2) * (y + 2) <= 1
|| (x - 2) * (x - 2) + (y + 2) * (y + 2) <= 1)
printf("height=10\n");
else
printf("height=0\n");
return 0;
}解析:
- 圆心 (−2,2) 对应
(x+2)²+(y−2)²——减负等于加。 - 用平方和 ≤ 1(即 r²)比开方更快、更准,还不用 math.h。
- 四个条件用
||连接:落在任意一个塔里都算 10 m。 &&与||混用时一定加括号,这里每个距离都用括号包住了。
🛠 随课练习(只给题不给答案)
🔮 猜输出
猜输出 1
#include <stdio.h>
int main()
{
int x = 5;
if (x > 3)
printf("A");
printf("B");
return 0;
}猜输出 2
#include <stdio.h>
int main()
{
int x = 0, y = 1;
if (x == 0)
if (y == 0) printf("A");
else printf("B");
return 0;
}猜输出 3
#include <stdio.h>
int main()
{
int a = 1, b = 2, c = 3, d = 4, m = 1, n = 1;
(m = a > b) && (n = c > d);
printf("%d %d\n", m, n);
return 0;
}猜输出 4
#include <stdio.h>
int main()
{
int n = 2;
switch (n)
{
case 1: printf("1");
case 2: printf("2");
case 3: printf("3"); break;
default: printf("4");
}
return 0;
}🛠 变式题
变式 1(照猫画虎):模仿例 4.2,输入两个整数,按从大到小输出。
变式 2(改需求):仿照例 4.6 的 switch 写法,写一个"分数 → 等级"的五档判断:90 及以上 A、80~89 B、70~79 C、60~69 D、60 以下 E。要求用 switch 写,而不是 if 链。
变式 3(翻译):输入 1~7 的整数,输出对应的星期英文名(1→Monday … 7→Sunday),其他数字输出 error。用 switch 写。
变式 4(补全):判断一个整数能否同时被 3 和 5 整除,请补全下面这个 if 的条件(假设 n 已经读入)。
if (____ && ____) /* 两个空都要填:一个管 3,一个管 5 */
printf("yes\n");
else
printf("no\n");🐛 改错题
改错 1
#include <stdio.h>
int main()
{
int x = 10;
if (x > 0);
printf("positive\n");
return 0;
}改错 2
#include <stdio.h>
int main()
{
int a = 0;
if (a = 1)
printf("equal\n");
else
printf("not equal\n");
return 0;
}改错 3
#include <stdio.h>
int main()
{
int score = 85;
switch (score)
{
case 90: printf("A\n"); break;
case 80: printf("B\n"); break;
default: printf("other\n");
}
return 0;
}(提示:程序能编译、能运行,但 85 分输出的是 other。想想 case 到底在比什么。)
📈 加练题(你随时喊,我随时追加到这里)
(暂无。想加练就说"再出几道 XX 题",我出的题会标上日期追加在这块。)
💬 问答区(你问过的问题 + 我的解答)
(暂无。你问的问题和我的解答会按 Q/A 整理进这里。)
该带走的 6 句话
- if 括号里是路牌:算出来非 0 就进,等于 0 就跳过;括号里可以放任何数值表达式,不一定是比较。
==是比较,=是赋值;判断相等时把常量写左边(5 == a),漏一个等号就会当场编译报错。- else 永远跟最近的、还没配对的 if 走,编译器不看你缩进——拿不准就加花括号。
&&左边为假、||左边为真时,右边根本不计算(短路),所以(m=a>b)&&(n=c>d)里 n 可能一点没变。- switch 只认整型和字符型表达式,case 后必须是常量;匹配到入口后不刹车就一路贯穿,所以每个 case 后面记得 break。
- 三种 if 形式 + switch 能表达一切选择;分段题先把边界一个个验一遍,浮点数判等要用
fabs(x) < 1e-6。
📚 教材覆盖清单(第4章,选择结构程序设计)
这张表把本课和教材逐节对上:从网页可以回查书页,从书页也能找到网页位置。标「未展开」的,就是教材里有、本课没讲的部分,已明确列出。
| 教材节号 | 标题 | 书页 | 网站对应 | 状态 |
|---|---|---|---|---|
| 4.1 | 选择结构和条件判断 | p.83–84 | 4.1 选择结构和条件判断 | 精讲 |
| 4.2 | 用if语句实现选择结构 | p.85–88 | 4.2 用 if 语句实现选择结构 | 精讲 |
| 4.2.1 | 用if语句处理选择结构举例 | p.85–86 | 4.2.1 用 if 语句处理选择结构举例 | 精讲 |
| 4.2.2 | if语句的一般形式 | p.87–88 | 4.2.2 if 语句的一般形式 | 精讲 |
| 4.3 | 关系运算符和关系表达式 | p.89 | 4.3 关系运算符和关系表达式 | 精讲 |
| 4.3.1 | 关系运算符及其优先次序 | p.90 | 4.3.1 关系运算符及其优先次序 | 精讲 |
| 4.3.2 | 关系表达式 | p.90 | 4.3.2 关系表达式 | 精讲 |
| 4.4 | 逻辑运算符和逻辑表达式 | p.90–93 | 4.4 逻辑运算符和逻辑表达式 | 精讲 |
| 4.4.1 | 逻辑运算符及其优先次序 | p.91 | 4.4.1 逻辑运算符及其优先次序 | 精讲 |
| 4.4.2 | 逻辑表达式 | p.92–93 | 4.4.2 逻辑表达式 | 精讲 |
| 4.5 | 条件运算符和条件表达式 | p.94–95 | 4.5 条件运算符和条件表达式 | 精讲 |
| 4.6 | 选择结构的嵌套 | p.96–98 | 4.6 选择结构的嵌套 | 精讲 |
| 4.7 | 用switch语句实现多分支选择结构 | p.99–101 | 4.7 用 switch 语句实现多分支选择结构 | 精讲 |
| 4.8 | 选择结构程序综合举例 | p.102–106 | 4.8 选择结构程序综合举例 | 精讲 |
| 习题 | 第4章书末习题 | p.107–109 | 本课「书上习题精讲」 | 逐题精讲(第1–12题) |
| 插图 | 本课范围内教材插图 | p.83–106 | 用文字/ASCII 重画 | 未逐张复刻 |
| 附录 | 附录 A–E | p.357–370 | 全书对照页 | 未单独成课 |
- 教材插图(流程图、内存示意图等)本课用文字/ASCII 重画,未逐张复刻,页码见上表。
- 附录 A–E(p.357–370)是速查表,未单独成课;全站对照页列出。
- 标「本课补充」的小节(先补地基、比喻、随课练习等)不是教材原文,是为理解而加的。