CC语言通关
第04课 · 要写代码
教材对照
第04课配套 · 纯代码

第04课 · 要写代码

if 三种形式、关系与逻辑运算、条件运算符、switch 多分支

25 段代码每行都有注释边敲边想
教材依据第4章《选择结构程序设计》书页 p.83–109
本课覆盖:教材第4章正文 + 书末习题(p.107–109)。标「教材 p.X」= 教材段落总结;「例题」= 教材例题;「习题」= 书末题目;「本课补充」= 非教材原文。
在全书对照表中查看 →

本章所有代码都能直接编译运行。每行后面的 // 注释解释这一行在干什么,照着敲一遍,比看十遍强。
输入格式按代码里的 scanf 来:有的用空格分隔,有的用逗号分隔,注释里都标了。

一、知识点代码

c
// ============ 1. if 单分支:求绝对值 ============
#include <stdio.h> // 包含输入输出头文件,才能用 scanf 和 printf
int main() // 主函数,程序从这里开始
{ // 主函数体开始
    int x; // 定义整型变量 x,用来存放输入的数
    scanf("%d", &x); // 从键盘读一个整数放进 x,& 表示取地址
    if (x < 0) // 单分支:如果 x 小于 0,路牌为"真"
        x = -x; // 真就走这一句:把 x 变成相反数
    printf("%d\n", x); // 输出 x,%d 表示按整数输出
    return 0; // 程序正常结束,向系统返回 0
} // 主函数体结束
c
// ============ 2. if-else 双分支:判断奇数偶数 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int n; // 定义整型变量 n
    scanf("%d", &n); // 读入一个整数
    if (n % 2 == 0) // 条件:n 除以 2 的余数等于 0,即偶数
        printf("even\n"); // 条件为真,走 if 这一支
    else // 否则(余数不为 0)
        printf("odd\n"); // 走 else 这一支
    return 0; // 结束
} // 函数体结束
c
// ============ 3. 多分支 if-else if:成绩分档 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int score; // 定义整型变量 score 存分数
    scanf("%d", &score); // 读入分数
    if (score >= 90) // 第一个路牌:90 分及以上
        printf("A\n"); // 走 A
    else if (score >= 80) // 否则再问:80 分及以上(此时必然小于 90)
        printf("B\n"); // 走 B
    else if (score >= 70) // 再问:70 分及以上
        printf("C\n"); // 走 C
    else if (score >= 60) // 再问:60 分及以上
        printf("D\n"); // 走 D
    else // 剩下的都不到 60
        printf("E\n"); // 走 E
    return 0; // 结束
} // 函数体结束
c
// ============ 4. 关系、逻辑表达式与短路求值 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int a = 3, b = 2, c = 1; // 定义并初始化三个整数
    int m = 1, n = 1; // m、n 用来观察短路,初值都设为 1
    printf("%d\n", a > b); // 3>2 为真,关系表达式的值是 1
    printf("%d\n", a > b > c); // 自左至右:(3>2)>1 即 1>1,值为 0
    printf("%d\n", a && b); // 两个都非 0,逻辑与为真,值为 1
    printf("%d\n", !a); // a 非 0 为真,取非得假,值为 0
    printf("%d\n", 0 < a < 10); // 数学写法在 C 里恒真:(0<3)<10 即 1<10,值为 1
    (m = a < b) && (n = c > b); // 左边 3<2 为假(0),&& 短路,右边不执行
    printf("%d %d\n", m, n); // 所以 m 变成 0,n 仍是原来的 1
    return 0; // 结束
} // 函数体结束
c
// ============ 5. 条件运算符 ? : ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int a, b, max; // 定义两个输入数和一个最大值
    scanf("%d%d", &a, &b); // 两个整数用空格隔开输入
    max = (a > b) ? a : b; // 条件表达式:a>b 为真取 a,否则取 b
    printf("max=%d\n", max); // 输出较大值
    printf("%d\n", (a > b) ? a - b : b - a); // 条件表达式也可以直接参与运算
    return 0; // 结束
} // 函数体结束
c
// ============ 6. 嵌套 if 与悬空 else ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int x = 0, y = 1; // 定义并初始化两个整数
    if (x > 0) // 外层 if:x 大于 0 吗?
        if (y > 0) printf("A\n"); // 内层 if:y 大于 0 吗?
        else       printf("B\n"); // 这个 else 配内层 if(离它最近且未配对)
    printf("----\n"); // 打印一条分隔线
    if (x > 0) // 同样的问题,这次用花括号限定范围
    { // 外层 if 的复合语句开始
        if (y > 0) printf("C\n"); // 内层 if 单独成一个块
    } // 外层 if 的复合语句结束
    else // 这个 else 配外层 if
        printf("D\n"); // 外层条件不成立时走这里
    return 0; // 结束
} // 函数体结束
c
// ============ 7. switch 基本用法:等级转分数段 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    char grade; // 定义字符变量存等级
    scanf("%c", &grade); // 读一个字符(A、B、C、D 之一)
    switch (grade) // 按 grade 的值直接跳到对应 case
    { // switch 语句体开始
        case 'A': printf("85~100\n"); break; // 匹配 A,输出后 break 跳出
        case 'B': printf("70~84\n");  break; // 匹配 B,输出后跳出
        case 'C': printf("60~69\n");  break; // 匹配 C,输出后跳出
        case 'D': printf("<60\n");    break; // 匹配 D,输出后跳出
        default : printf("error\n"); // 都不匹配时走这里
    } // switch 语句体结束
    return 0; // 结束
} // 函数体结束
c
// ============ 8. switch 的贯穿:故意不写 break ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int n = 2; // 假设 n 等于 2
    switch (n) // 按 n 的值找入口
    { // switch 语句体开始
        case 1: printf("1"); // 不匹配,跳过
        case 2: printf("2"); // 从这里进入,打印 2
        case 3: printf("3"); break; // 没有 break,继续打印 3,然后才跳出
        default: printf("4"); // 如果连 break 都没有,还会继续打印 4
    } // switch 语句体结束
    printf("\n"); // 输出换行
    return 0; // 结束
} // 函数体结束

二、课后题 · 代码题

c
// ============ 习题 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; // b 来挑战,赢了就更新 max
    if (c > max) max = c; // c 再来挑战,赢了再更新
    printf("max=%d\n", max); // 输出最后的擂主
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 5:求小于 1000 的正数的平方根(取整数部分)============
#include <stdio.h> // 输入输出头文件
#include <math.h> // sqrt 函数在这个头文件里
int main() // 主函数入口
{ // 函数体开始
    double x; // 定义双精度变量存输入
    scanf("%lf", &x); // 读一个双精度数
    if (x > 0 && x < 1000) // 两个条件都要满足:正数且小于 1000
        printf("%d\n", (int)sqrt(x)); // sqrt 求平方根,(int) 强制取整数部分
    else // 输入不合法
        printf("input error\n"); // 提示错误
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 6:分段函数 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    float x, y; // x 是自变量,y 是函数值
    scanf("%f", &x); // 读入 x
    if (x < 1) // 第一段:x 小于 1
        y = x; // y = x
    else if (x < 10) // 第二段:1 <= x < 10(前面的已排除)
        y = 2 * x - 1; // y = 2x - 1
    else // 第三段:x >= 10
        y = 3 * x - 11; // y = 3x - 11
    printf("x=%.2f,y=%.2f\n", x, y); // 输出,保留两位小数
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 8:百分制转等级 A~E(switch 版)============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int score; // 定义分数
    scanf("%d", &score); // 读入分数
    switch (score / 10) // 用十位数当入口:90~99 得到 9,100 得到 10
    { // switch 语句体开始
        case 10: // 100 分单独处理
        case 9:  printf("A\n"); break; // 90~100 都是 A
        case 8:  printf("B\n"); break; // 80~89 是 B
        case 7:  printf("C\n"); break; // 70~79 是 C
        case 6:  printf("D\n"); break; // 60~69 是 D
        default: printf("E\n"); // 剩下的都是 E
    } // switch 语句体结束
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 10(1):按利润提成算奖金(if 版)============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    double i, bonus; // i 是利润,bonus 是奖金
    scanf("%lf", &i); // 读入利润
    if (i <= 100000) // 第一段:10 万以内
        bonus = i * 0.1; // 全额提 10%
    else if (i <= 200000) // 第二段:10~20 万
        bonus = 10000 + (i - 100000) * 0.075; // 前 10 万封顶 1 万,超出部分 7.5%
    else if (i <= 400000) // 第三段:20~40 万
        bonus = 17500 + (i - 200000) * 0.05; // 前面封顶 1.75 万,超出部分 5%
    else if (i <= 600000) // 第四段:40~60 万
        bonus = 27500 + (i - 400000) * 0.03; // 前面封顶 2.75 万,超出部分 3%
    else if (i <= 1000000) // 第五段:60~100 万
        bonus = 33500 + (i - 600000) * 0.015; // 前面封顶 3.35 万,超出部分 1.5%
    else // 第六段:100 万以上
        bonus = 39500 + (i - 1000000) * 0.01; // 前面封顶 3.95 万,超出部分 1%
    printf("bonus=%10.2f\n", bonus); // 输出奖金,宽度 10、两位小数
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 10(2):同样的奖金题,switch 版 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    double i, bonus; // i 是利润,bonus 是奖金
    int c; // c 是把利润按"十万"分段的编号
    scanf("%lf", &i); // 读入利润
    c = (int)(i / 100000); // 除以 10 万后取整,得到 0、1、2……
    switch (c) // 按 c 跳到对应段
    { // switch 语句体开始
        case 0:  bonus = i * 0.1; break; // 0~10 万
        case 1:  bonus = 10000 + (i - 100000) * 0.075; break; // 10~20 万
        case 2: // 20~30 万
        case 3:  bonus = 17500 + (i - 200000) * 0.05; break; // 30~40 万,与上共用
        case 4: // 40~50 万
        case 5:  bonus = 27500 + (i - 400000) * 0.03; break; // 50~60 万,与上共用
        case 6: // 60~70 万
        case 7: // 70~80 万
        case 8: // 80~90 万
        case 9:  bonus = 33500 + (i - 600000) * 0.015; break; // 90~100 万,四个共用
        default: bonus = 39500 + (i - 1000000) * 0.01; // 100 万以上
    } // switch 语句体结束
    printf("bonus=%10.2f\n", bonus); // 输出奖金
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 11:输入 4 个整数,按从小到大输出 ============
#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; } // 保证 a <= b
    if (a > c) { t = a; a = c; c = t; } // 保证 a <= c,此时 a 最小
    if (a > d) { t = a; a = d; d = t; } // 保证 a <= d,a 确定为最小
    if (b > c) { t = b; b = c; c = t; } // 保证 b <= c
    if (b > d) { t = b; b = d; d = t; } // 保证 b <= d,b 确定为次小
    if (c > d) { t = c; c = d; d = t; } // 保证 c <= d,全部排好
    printf("%d %d %d %d\n", a, b, c, d); // 按序输出
    return 0; // 结束
} // 函数体结束
c
// ============ 习题 12:判断点落在哪个圆塔里,求建筑高度 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    double x, y; // 点的横、纵坐标
    scanf("%lf,%lf", &x, &y); // 两个坐标用逗号分隔输入
    if ((x - 2) * (x - 2) + (y - 2) * (y - 2) <= 1 // 到圆心 (2,2) 的距离平方 <= 1
        || (x + 2) * (x + 2) + (y - 2) * (y - 2) <= 1 // 到圆心 (-2,2)
        || (x + 2) * (x + 2) + (y + 2) * (y + 2) <= 1 // 到圆心 (-2,-2)
        || (x - 2) * (x - 2) + (y + 2) * (y + 2) <= 1) // 到圆心 (2,-2)
        printf("height=10\n"); // 落在任一塔内,高度 10 米
    else // 四个都不满足
        printf("height=0\n"); // 塔外高度为 0
    return 0; // 结束
} // 函数体结束

三、我出的题 · 随课练习

🔮 猜输出

c
// ============ 猜输出 1:if 到底管到哪一句 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int x = 5; // 定义并初始化 x 为 5
    if (x > 3) // 条件成立时会怎样?
        printf("A"); // 这一句受 if 控制
    printf("B"); // 这一句呢?注意缩进不代表从属关系
    printf("\n"); // 换行
    return 0; // 结束
} // 函数体结束
c
// ============ 猜输出 2:悬空 else ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int x = 0, y = 1; // 初始化
    if (x == 0) // 外层条件成立
        if (y == 0) printf("A"); // 内层条件不成立
        else        printf("B"); // 这个 else 跟哪个 if 配对?
    printf("\n"); // 换行
    return 0; // 结束
} // 函数体结束
c
// ============ 猜输出 3:短路求值 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int a = 1, b = 2, c = 3, d = 4; // 四个整数
    int m = 1, n = 1; // m、n 初值都是 1
    (m = a > b) && (n = c > d); // 先算左边,再看要不要算右边
    printf("%d %d\n", m, n); // 输出 m 和 n
    return 0; // 结束
} // 函数体结束

🛠 变式题

c
// ============ 变式 1:输入两个数,按从大到小输出(补全交换)============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    float a, b, t; // 两个数和临时变量
    scanf("%f,%f", &a, &b); // 逗号分隔输入
    if (a < b) // 前小后大,说明顺序反了
    { // 需要交换
        // TODO:在这里写三句交换代码
    } // 交换结束
    printf("%5.2f,%5.2f\n", a, b); // 输出
    return 0; // 结束
} // 函数体结束
c
// ============ 变式 2:输入 1~7,输出星期英文名(补全 case)============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int day; // 1~7 的整数
    scanf("%d", &day); // 读入
    switch (day) // 按 day 跳转
    { // switch 体开始
        case 1: printf("Monday\n");  break; // 已给样例
        // TODO:补 case 2 到 case 7
        default: printf("error\n"); // 其他数字
    } // switch 体结束
    return 0; // 结束
} // 函数体结束
c
// ============ 变式 3:补全条件——能同时被 3 和 5 整除 ============
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int n; // 待判断的整数
    scanf("%d", &n); // 读入
    if (1) // TODO:把 1 换成正确的复合条件
        printf("yes\n"); // 满足时输出 yes
    else // 否则
        printf("no\n"); // 输出 no
    return 0; // 结束
} // 函数体结束

🐛 改错题

c
// ❌ 错误示例(故意)
// 错在哪:if 后面多了一个分号,if 管的是一个空语句,printf 变成无条件执行
// 怎么改:把 if (x > 0); 后面的分号删掉
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int x = 10; // 定义 x
    if (x > 0); // 这里多了分号
        printf("positive\n"); // 这句其实和 if 无关
    return 0; // 结束
} // 函数体结束
c
// ❌ 错误示例(故意)
// 错在哪:if (a = 1) 是赋值,不是比较;a 被赋成 1,表达式值为 1,永远为真
// 怎么改:写成 if (a == 1),或者把常量写左边 if (1 == a)
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int a = 0; // a 初值为 0
    if (a = 1) // 赋值表达式,恒为真
        printf("equal\n"); // 永远走这里
    else // 永远走不到
        printf("not equal\n"); // 本应输出这句
    return 0; // 结束
} // 函数体结束
c
// ❌ 错误示例(故意)
// 错在哪:case 90 只匹配 90 这个精确值,85 不等于 90,所以落到 default
// 怎么改:改成 switch (score / 10),用十位数匹配,case 9 管 90~99
#include <stdio.h> // 输入输出头文件
int main() // 主函数入口
{ // 函数体开始
    int score = 85; // 分数 85
    switch (score) // 用原始的分数当开关
    { // switch 体开始
        case 90: printf("A\n"); break; // 只有正好 90 才匹配
        case 80: printf("B\n"); break; // 只有正好 80 才匹配
        default: printf("other\n"); // 85 落到这里
    } // switch 体结束
    return 0; // 结束
} // 函数体结束

四、加练题

(暂无。想加练就说"再出几道 XX 题",我出的题会标上日期追加在这块。)