C++ 魔法代码学院:第 14 课——真题大闯关(一):找 Bug 大赛

2026-01-20
47

—— 谁是火眼金睛的代码神探?

  • 课时时长:90 分钟
  • 核心目标

    1. 复习全览:综合回顾变量、运算、判断、循环的所有易错点。
    2. 读题训练:锻炼“人脑编译器”能力,不靠电脑也能看出代码结果。
    3. 扫除盲区:重点攻克 GESP 一级考试中“能运行但结果不对”的逻辑陷阱。
  • 形式:分组竞赛(红队 vs 蓝队)。

  • 所需教具
    • 打印好的“病历卡”(印有错误代码的纸)。
    • 红笔(用来圈 Bug)。
    • “Bug 猎人”勋章(贴纸)。

课程时间表

环节 时间 内容 教学隐喻/活动
开场 10 min 规则介绍与分组 “捉虫特工队集结”
Round 1 20 min 青铜级 Bug:语法与变量 “粗心的抄写员”
Round 2 20 min 白银级 Bug:运算与判断 “固执的数学家”
Round 3 25 min 黄金级 Bug:循环陷阱 “停不下来的跑步机”
Round 4 10 min 王者级 Bug:综合逻辑 GESP 原题模拟
颁奖 5 min 总结与发奖 授予“Bug 猎人”称号

详细教学流程

1. 开场:捉虫特工队 (10分钟)

  • 情景引入: > “魔法学院的图书馆被一群‘代码虫’入侵了!很多咒语书都被它们咬坏了,导致魔法失效。今天,我们要组成特工队,把这些虫子全找出来!”

  • 分组:全班分为两队(或三队)。

  • 规则
    • 每轮展示 3 段代码。
    • 抢答指出错误在哪里,并说明原因。
    • 答对加 1 星,解释清楚原理加 2 星。

2. Round 1:青铜级 Bug —— 粗心大意 (20分钟)

  • 核心考点:分号、变量初始化、输入输出方向。
  • 病例 A(致命的分号)

    if (score > 90); {  // 🐛 错误:多写了分号
            cout << "优秀";
    }
    

    • 病症:不管考多少分,都会打印“优秀”。
    • 诊断if 后面加分号,意味着 if 语句结束了。下面的 {} 变成了谁都可以进的公共场所。
  • 病例 B(垃圾堆里捡数字)

    int sum;         // 🐛 错误:未初始化
    for(int i=1; i<=10; i++) {
            sum += i;
    }
    cout << sum;
    

    • 病症:输出一个奇怪的巨大数字(如 32760)。
    • 诊断sum 没清零,里面装的是上次留下的垃圾值。**必须写 int sum = 0;**
  • 病例 C(方向搞反)

    int a;
    cin << a;       // 🐛 错误:方向反了
    

    • 诊断cin 是流入 >>cout 是流出 <<

3. Round 2:白银级 Bug —— 逻辑黑洞 (20分钟)

  • 核心考点:赋值与相等、整数除法。

    • 病例 D(永远的满分)

      if (score = 100) {  // 🐛 错误:用了赋值号 =
              cout << "满分";
      }
      

    • 病症:不管输入几分,都显示“满分”,而且 score 变成了 100。

    • 诊断= 是把 100 塞给 score,== 才是问是不是 100。
  • 病例 E(消失的小数)

    int a = 5;
    int b = 2;
    double c = a / b;  // 🐛 错误:整数相除
    cout << c;
    

    • 病症:输出 2 而不是 2.5
    • 诊断:两个整数打架,结果还是整数。必须有 1.0 参与1.0 * a / b
  • 病例 F(判断范围)

    if (10 < a < 20) {  // 🐛 错误:数学写法
            cout << "在范围内";
    }
    

    • 病症:逻辑混乱。
    • 诊断:C++ 一次只能比一场。必须用 && 连接:if (a > 10 && a < 20)

4. Round 3:黄金级 Bug —— 循环噩梦 (25分钟)

  • 核心考点:死循环、Off-by-one(多一次少一次)。
  • 病例 G(根本停不下来)

    int i = 10;
    while (i > 0) {
            cout << i << " ";
            // 🐛 错误:忘了写 i--
    }
    

    • 病症:屏幕疯狂刷屏 10 10 10 ...,电脑死机。
    • 诊断:吃包子忘了咽下去(没有改变循环变量),这就叫死循环
  • 病例 H(多跑了一圈)

    • 题目要求:输出 1 到 10。
    for (int i = 1; i < 10; i++) { // 🐛 错误:判断条件写错
            cout << i << " ";
    }
    
    • 病症:只输出到 9。
    • 诊断i < 10 意味着 i 到 10 的时候就被赶走了。要写 i <= 10 或者 i < 11
  • 病例 I(continue 的陷阱)

    int i = 1;
    while (i <= 5) {
            if (i == 3) continue; // 🐛 错误:跳过了 i++
            cout << i;
            i++;
    }
    

    • 病症:输出 1 2 然后卡死。
    • 诊断:在 while 里用 continue,如果不先把步子迈了(i++),就会原地踏步死循环。

5. Round 4:王者级 Bug —— 综合模拟 (10分钟)

  • 形式:直接拿出一道 GESP 一级真题的阅读程序题(修改版)。
  • 题目: > 阅读下面的程序,如果输入 7,输出结果是多少?

    int n;
    cin >> n;
    int ans = 0;
    for (int i = 1; i <= n; i++) {
            if (i % 2 == 0) {
                    ans = ans + i;
            } else {
                    ans = ans - i;
            }
    }
    cout << ans;
    
  • 引导分析(Trace Table)

    • 不要瞎猜!画表!
    • i=1 (奇): ans = 0 - 1 = -1
    • i=2 (偶): ans = -1 + 2 = 1
    • i=3 (奇): ans = 1 - 3 = -2
    • i=4 (偶): ans = -2 + 4 = 2
    • ...
    • 规律:每两个数一组,结果增加 1。
    • i=7 (奇): 结果是 -4。

课后福利:避坑口诀卡

老师可以将以下内容打印成小卡片发给学生:

  • GESP 一级护身符
    1. 分号不乱加iffor 后面别手抖。
    2. 等于要双份:判断相等用 ==
    3. 罐子要清洗sum 必须 = 0
    4. 整数很固执5/2 等于 2,想要小数乘 1.0
    5. 循环防死机:检查 i 变没变?

给教练的教学话术建议

  1. 关于“读代码”的重要性

    • 告诉学生:“在信奥比赛里,有一半的分数是不用敲键盘的(初赛笔试)。如果你能一眼看出别人的 Bug,你就是顶级黑客。”
  2. 小黄鸭调试法 (Rubber Duck Debugging)

    • 如果在找 Bug 环节学生卡住了,让他们试着把代码讲给桌子上的铅笔听
    • “亲爱的铅笔,第一行代码是...它的意思是...哎呀!我发现错了!”
    • 通过大声朗读逻辑,往往能自己发现错误。
  3. 鼓励犯错

    • 今天的课就是为了现在犯错,考试不错
    • “看,这个死循环 Bug 多可爱,幸好我们在课堂上抓住了它,没让它跑到考场上去。”