🔒

C5-3 课程拓展解析

本页面包含代码填空4关的完整参考答案、随堂练习答案与家长辅导建议。
请输入本讲访问密码:

密码错误,请重试

📚 C5-3 字符串模拟与输出调试 · 拓展解析

课程辅导解析(家长端) · 含代码填空、随堂练习全部答案

一、代码填空(字符串消消乐大冒险)4关完整答案

每关含:题目内容、解题思路、完整代码(带注释)、易错点、家长辅导建议。

第1关:字符串小魔术

输入一个字符串 s,输出它的长度、第一个字符、前3个字符。输入"hello"应输出:长度5、首字符h、前3个hel。
✅ 填空答案:① s.size() ② s[0] ③ s.substr(0,3)
解题思路:这是字符串操作"四件套"的入门。求长度用 size();下标从0开始,第一个字符是 s[0];截取子串用 substr(起点, 长度),前3个就是 substr(0,3)。
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;
    cout << "长度:" << s.size() << endl;        // ★ size() 求字符串长度
    cout << "首字符:" << s[0] << endl;         // ★ 下标从0开始,第一个字符是 s[0]
    cout << "前3个:" << s.substr(0, 3) << endl; // ★ substr(起点,长度) 取前3个
    return 0;
}
⚠️ 易错点:学生最常把第一个字符写成 s[1]。反复强调:字符串下标从 0 开始,不是从 1 开始!
家长辅导:让孩子把 substr 第二个参数理解成"要截几个",不是"截到第几个位置"。可以用"hello"手动数一遍:位置0=h,1=e,2=l,3=l,4=o。

第2关:有重叠的子串计数

输入字符串 s 和子串 p,统计 p 在 s 中出现多少次(允许重叠)。s="aaaa", p="aa" 结果应为 3。
✅ 填空答案:① p.size() ② s.substr(i,m) ③ cnt++
解题思路:用 for 循环枚举每个起始位置 i,从 i 起截 m 个字符与 p 比较,相等就 cnt++。有重叠时 for 循环的 i 照常 +1,这样每个位置都检查一遍。
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s, p;
    cin >> s >> p;
    int cnt = 0;
    int m = p.size();                // ★ 子串长度
    for (int i = 0; i + m <= s.size(); i++) {
        if (s.substr(i, m) == p) {   // ★ 从i起截m个字符,与p比较
            cnt++;                   // ★ 匹配成功:计数+1
        }                           // 有重叠!for循环的i照常+1继续找
    }
    cout << cnt << endl;
    return 0;
}
⚠️ 易错点:循环条件写成 i <= s.size() 会越界。正确写法是 i + m <= s.size(),保证从 i 起还能截出 m 个字符。
家长辅导:用"aaaa"手动模拟:位置0✓、位置1✓、位置2✓,位置3不够2个字符,所以是3。让孩子理解"允许重叠"就是相邻位置也能各自计数。

第3关:无重叠的子串计数

输入 s 和 p,统计 p 出现次数(不允许重叠)。s="aaaa", p="aa" 结果应为 2。
✅ 填空答案:① i += m ② i++
解题思路:与有重叠的关键区别:找到一次匹配后,要跳过整个匹配部分(i += m);没找到才 i++ 往后走一步。因为循环体里手动控制 i,for 括号里不能再写 i++。
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s, p;
    cin >> s >> p;
    int cnt = 0;
    int m = p.size();
    for (int i = 0; i + m <= s.size(); ) {   // ★ 注意:循环体里手动控制i,这里不写i++
        if (s.substr(i, m) == p) {
            cnt++;
            i += m;        // ★ 无重叠:找到后跳过整个匹配部分
        } else {
            i++;           // ★ 没找到:往后走一步
        }
    }
    cout << cnt << endl;
    return 0;
}
⚠️ 易错点:在 for 括号里还写 i++,导致 i 被加两次(循环体加一次、for 再加一次),结果漏计数。
家长辅导:用"aaaa"模拟:位置0找到"aa"→跳到位置2;位置2找到"aa"→跳到位置4结束,所以是2。对比第2关的3,让孩子说出区别在哪。

第4关:开心消消乐

输入一个字符串,不断消除连续3个相同字符,直到无法消除,输出最终字符串。
✅ 填空答案:① s[i+2] ② s.replace(i,3,"") ③ break
解题思路:用 while(changed) 多轮扫描。每轮从头检查是否有 s[i]==s[i+1]==s[i+2],发现就用 replace(i,3,"") 消掉,并置 changed=true,然后 break 从头重扫——因为消除后左右拼接可能形成新的三连。
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;
    bool changed = true;
    while (changed) {
        changed = false;            // 假设这一轮没有可消的
        for (int i = 0; i + 2 < s.size(); i++) {
            if (s[i] == s[i+1] && s[i+1] == s[i+2]) {  // ★ 连续3个相同
                s.replace(i, 3, "");    // ★ 从i起消掉3个字符
                changed = true;         // 发生了消除,还要再来一轮
                break;                  // ★ 字符串变了,从头重新扫描
            }
        }
    }
    cout << s << endl;
    return 0;
}
⚠️ 易错点:消掉后不 break,继续在原 i 往后扫会漏判新拼接出的三连;循环条件 i+2<s.size() 不能写成 i<s.size()(会越界访问 s[i+2])。
家长辅导:用"aabbba"手动演示:bbba 消掉中间bbb → 剩"aa";若不重扫就漏掉后续。告诉孩子 replace(x,3,"") 就是"把3个字符删掉"。

二、随堂练习答案(5单选 + 3判断,满分80)

与"随堂练习"页题目一一对应。

单选1:s="hello",s.substr(1,3) 的结果?

✅ 答案:B("ell")
解析:从位置1(第二个字符 e)开始截3个:e、l、l,即"ell"。注意第二个参数是"截取几个"。

单选2:"aaaa" 中 "aa" 有重叠计数?

✅ 答案:C(3次)
解析:位置0✓、1✓、2✓,位置3不够,共3次。有重叠=找到后 i++ 继续找。

单选3:"aaaa" 中 "aa" 无重叠计数?

✅ 答案:B(2次)
解析:位置0找到后跳过2个到位置2,位置2又找到,跳到位置4结束,共2次。

单选4:报错 "expected '}' at end of input" 最可能原因?

✅ 答案:B(少写了一个右大括号 })
解析:expected '}' 表示编译器在文件末尾还在等一个 }。报错行号可能不准,要往上多找几行。

单选5:编译通过但结果不对,最好的调试方法?

✅ 答案:B(用 cout 打印中间变量)
解析:这是逻辑错误。在关键位置加 cout 打印中间变量,一步步定位哪步跑偏。一次只改一个地方!

判断1:s.size() 得长度,第一个字符下标是1。

❌ 答案:错误
解析:长度对,但下标从0开始,第一个字符是 s[0]。

判断2:replace(i,3,"") 可删掉从 i 起的3个字符。

✅ 答案:正确
解析:把3个字符替换成空字符串"",就相当于删掉。消消乐就是用这个。

判断3:编译错误报的行号一定就是错误所在行。

❌ 答案:错误
解析:行号不一定准。少写 } 可能报在文件最后一行,要学会往上多看几行。

三、课程穿插选择题答案

课程第6页:无重叠统计,找到 aba 后下一次从哪开始?

✅ 答案:A(从最后一个字符的下一个,即 a[3] 开始)
解析:找到 aba 占了 a[0..2],无重叠时下一次应从匹配串之后的 a[3] 开始。

课程第11页:buggy.cpp 最直接的语法错误?

✅ 答案:C(第四行 int result=a+b 后缺分号)
解析:第4行末尾缺分号是最直接的语法错误,编译会报 expected ';'。

课程第20页:even.cpp 描述正确的是?

✅ 答案:A(不报错但逻辑不对,累加的不是1~10所有偶数的和)
解析:i 从0到9、i%2==0,累加的是 0+2+4+6+8=20,不是 2+4+6+8+10=30。

四、家长辅导要点总结

📌 这节课最需要让孩子记住的8件事

1. 字符串下标从 0 开始,第一个字符是 s[0]
2. size() 求长度;substr(起点,长度) 截子串;replace(起点,长度,"") 删字符
3. 有重叠计数:找到后 i++;无重叠计数:找到后 i += m
4. 循环枚举窗口条件:i + m <= s.size(),防止越界
5. 消消乐:replace(i,3,"") 消除后必须 break 从头重扫
6. 编译错误(如 expected '}')行号可能不准,要往上多找几行
7. 编译通过 ≠ 结果正确;逻辑错误用 cout 打印中间变量调试
8. 调试时一次只改一个地方,改完就运行验证
家庭练习建议:让孩子用"ababa"、"aabbcc"等短字符串手动模拟有重叠/无重叠计数,再对照程序输出。鼓励孩子在代码里加 cout 打印 i 和 cnt,观察循环过程——这正是"输出调试法"的核心。