Files
ClassFeedback/.claude/lesson/CSP03/CSP03-06_string使用1.md
chengzi efa1e6aa60 更新课程内容与课评反馈(2026春季)
- 更新K4课程README与课程目录
- 更新AI03 SOLO模式体验课程内容
- 补录各班级学生出勤登记
- 更新课评汇总归档
- 新增CSP03 string使用课程笔记
- 新增备份脚本与逐字稿输出
2026-04-17 21:04:51 +08:00

13 KiB
Raw Blame History

CSP03-06 string 使用1

一、课程简介5分钟

🎯 课程目标

  1. 理解 stringchar 数组的区别与联系
  2. 掌握 string 的声明、初始化、输入输出和基本操作
  3. 掌握字符串大小写转换的方法
  4. 掌握 string 的搜索(find)、分割和替换操作

📚 核心知识点

  • stringchar[] 的区别(动态 vs 静态,操作方便性)
  • string 的赋值(=)、拼接(++=)、比较(==<>
  • string 的长度:s.size() / s.length()
  • 下标访问:s[i]
  • 大小写转换:tolower / toupper 配合 for 循环
  • 搜索:s.find(sub)s.find(sub, pos)
  • 替换:s.replace(pos, len, newStr)
  • 分割:按字符或分隔符拆分字符串

二、知识回顾10分钟

👩‍🏫 教师引导

上节课我们用 char 数组处理字符串,虽然能用,但挺麻烦的——要手动管理 \0、require 头文件、还要防止越界……

C++ 给我们提供了更好的工具:string

string,可以直接用 + 拼接字符串,用 == 比较,不需要 strcatstrcmp,方便多了!

今天就来学习 string 的强大功能!

互动复习:

  • 用 char 数组,如何拼接 "hello" 和 " world"?(用 strcat
  • 用 char 数组,如何判断两个字符串相等?(用 strcmp == 0
  • 今天用 string这些操作只需要 +==

三、新知讲解45分钟

1. 新知导入 🎬

想象一下char 数组就像固定大小的盒子,放东西之前要提前想好放多大;

string 就像一个弹性袋子,想放多少放多少,自动扩容!

不仅如此,string 还内置了海量实用功能:查找、替换、截取……一个 #include <string> 搞定一切!


2. 知识点讲解

2.1 string 与 char 数组的区别

特性 char a[] string s
大小 定义时固定 动态可变
拼接 strcat(a, b) a + b
比较 strcmp(a, b) a == ba < b
长度 strlen(a) s.size() / s.length()
读含空格 cin.getline getline(cin, s)

2.2 string 的声明与初始化

#include <string>   // 需要此头文件
using namespace std;

string s1;              // 空字符串
string s2 = "hello";   // 直接初始化
string s3 = s2;        // 拷贝初始化
string s4(5, 'a');     // "aaaaa"

2.3 基本操作

赋值与拼接:

string s = "hello";
s += " world";     // s = "hello world"
s = s + "!";       // s = "hello world!"

比较:

string a = "apple", b = "banana";
if (a < b) cout << "apple comes first";  // 字典序比较
if (a == b) cout << "equal";

长度:

string s = "hello";
cout << s.size();    // 5
cout << s.length();  // 5两者等价

下标访问:

string s = "hello";
cout << s[0];    // 'h'
s[0] = 'H';     // s = "Hello"

输入输出:

string s;
cin >> s;             // 读到空格停止
getline(cin, s);      // 读整行(含空格)
cout << s << endl;

2.4 字符串大小写转换

string 没有直接的大小写转换函数,需要遍历每个字符:

#include <cctype>
string s = "Hello World";

// 全转小写
for (int i = 0; i < s.size(); i++) {
    s[i] = tolower(s[i]);
}
// s = "hello world"

// 全转大写
for (char &c : s) {   // 范围 for 循环写法
    c = toupper(c);
}
// s = "HELLO WORLD"

2.5 字符串搜索 find

s.find(sub) 返回子串 sub 第一次出现的起始下标,若不存在返回 string::npos(约等于 -1 的极大数)。

string s = "hello world hello";
int pos = s.find("hello");    // pos = 0
int pos2 = s.find("hello", 1); // 从位置1开始找pos2 = 12
int pos3 = s.find("xyz");     // 找不到,返回 string::npos

if (pos3 == string::npos) cout << "未找到";

遍历找所有出现位置:

string s = "abcabcabc";
string sub = "bc";
int pos = 0;
while ((pos = s.find(sub, pos)) != string::npos) {
    cout << pos << " ";
    pos++;  // 继续往后找
}
// 输出1 4 7

2.6 字符串替换 replace

s.replace(pos, len, newStr) 从位置 pos 开始,替换 len 个字符为 newStr

string s = "hello world";
s.replace(6, 5, "C++");  // 从位置6删5个字符替换为"C++"
// s = "hello C++"

2.7 简单字符串分割

C++ 的 string 没有内置 split 函数,常用方法:

按空格分割(提取单词):

string line = "hello world foo";
string word;
// 用 istringstream 分割
#include <sstream>
istringstream ss(line);
while (ss >> word) {
    cout << word << endl;
}
// 输出hello / world / foo

手动按字符分割:

string s = "a,b,c,d";
char delim = ',';
string cur = "";
for (int i = 0; i <= s.size(); i++) {
    if (i == s.size() || s[i] == delim) {
        cout << cur << endl;  // 输出当前段
        cur = "";
    } else {
        cur += s[i];
    }
}

3. GESP 真题演练

抢答题 1选择题

以下代码的输出是?

string s = "abcde";
cout << s.find("cd");

A. 0 B. 1 C. 2 D. 3

答案C
解析:"cd" 在 "abcde" 中从下标 2 开始find 返回 2。

判断题 2

string s = "hello"; s += " world"; 执行后,s.size() 返回 11。

答案:✓(正确)
解析:"hello world" 有 11 个字符(含中间空格)。

抢答题 3

以下代码中,如何判断字符串 s 中不包含子串 "abc"

string s = "xyzdef";
// 你的判断语句

答案: if (s.find("abc") == string::npos)


4. 进阶扩展

string 的常用操作备忘表:

操作 代码示例 说明
长度 s.size() 字符数
清空 s.clear() 清空字符串
是否为空 s.empty() 返回 bool
截取子串 s.substr(pos, len) 下节课讲
插入 s.insert(pos, str) 在 pos 前插入 str
删除 s.erase(pos, len) 删除 pos 起 len 个字符

字符串与数字互转:

// 数字转字符串C++11
string s = to_string(123);   // s = "123"

// 字符串转数字
int n = stoi("456");          // n = 456
double d = stod("3.14");      // d = 3.14

四、课堂练习45分钟🎈

练习 1基础字符串拼接

题目描述:

输入两个字符串,将它们拼接在一起输出。

输入格式:

  • 两行各一个字符串(不含空格,长度 ≤ 100

输出格式:

  • 拼接后的字符串

样例输入:

hello
world

样例输出:

helloworld

题解代码:

#include <iostream>
#include <string>
using namespace std;
int main() {
    string a, b;
    cin >> a >> b;
    cout << a + b << endl;
    return 0;
}

练习 2基础字符串全转小写

题目描述:

输入一行字符串,将其中所有大写字母转为小写,输出结果。

输入格式:

  • 一行字符串(长度 ≤ 1000

输出格式:

  • 转换后的字符串

样例输入:

Hello World! 123

样例输出:

hello world! 123

题解代码:

#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
    string s;
    getline(cin, s);
    for (int i = 0; i < s.size(); i++) s[i] = tolower(s[i]);
    cout << s << endl;
    return 0;
}

练习 3综合查找子串位置

题目描述:

输入主字符串 s 和子串 t找出 t 在 s 中第一次出现的位置0-indexed。若不存在输出 -1。

输入格式:

  • 第一行主字符串 s长度 ≤ 1000
  • 第二行子串 t长度 ≤ 100

输出格式:

  • 第一次出现的下标,若不存在输出 -1

样例输入:

hello world hello
world

样例输出:

6

题解代码:

#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, t;
    getline(cin, s);
    getline(cin, t);
    int pos = s.find(t);
    if (pos == string::npos) cout << -1 << endl;
    else cout << pos << endl;
    return 0;
}

练习 4综合统计子串出现次数

题目描述:

输入主串 s 和模式串 t统计 t 在 s 中出现的次数(允许重叠)。

输入格式:

  • 第一行主串 s
  • 第二行模式串 t

输出格式:

  • 出现次数

样例输入:

aaaa
aa

样例输出:

3

题解代码:

#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, t;
    cin >> s >> t;
    int cnt = 0, pos = 0;
    while ((pos = s.find(t, pos)) != string::npos) {
        cnt++;
        pos++;  // 允许重叠
    }
    cout << cnt << endl;
    return 0;
}

练习 5进阶字符串替换所有子串

题目描述:

输入主串 s以及旧子串 old 和新子串 newStr将 s 中所有 old 替换为 newStr输出结果。

输入格式:

  • 第一行主串 s长度 ≤ 1000
  • 第二行 old长度 ≤ 50
  • 第三行 newStr长度 ≤ 50

输出格式:

  • 替换后的字符串

样例输入:

hello world hello
hello
hi

样例输出:

hi world hi

题解代码:

#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, old_s, new_s;
    getline(cin, s);
    getline(cin, old_s);
    getline(cin, new_s);
    int pos = 0;
    while ((pos = s.find(old_s, pos)) != string::npos) {
        s.replace(pos, old_s.size(), new_s);
        pos += new_s.size();  // 跳过新插入的内容,避免死循环
    }
    cout << s << endl;
    return 0;
}

五、课堂总结5分钟🌟

今天我们掌握了 C++ 的 string 类,这是处理字符串的强力工具!

核心操作速查:

  • 拼接:s1 + s2s1 += s2
  • 比较:s1 == s2s1 < s2(字典序)
  • 长度:s.size()
  • 搜索:s.find(sub),找不到返回 string::npos
  • 替换:s.replace(pos, len, newStr)
  • 大小写转换:用循环 + tolower/toupper

下节课我们继续深入——提取子串、判断对称(回文),以及更复杂的字符串综合应用!


六、课后作业与拓展10分钟

📝 课后作业3道

作业 1判断两字符串是否相等不区分大小写

输入两个字符串,忽略大小写比较是否相等。相等输出 YES,否则 NO

样例输入:

Hello
hello

样例输出: YES

#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
    string a, b;
    cin >> a >> b;
    for (char &c : a) c = tolower(c);
    for (char &c : b) c = tolower(c);
    cout << (a == b ? "YES" : "NO") << endl;
    return 0;
}

作业 2字符串中是否包含某子串

输入主串和子串,判断子串是否在主串中出现,是输出 YES,否则 NO

样例输入:

helloworld
world

样例输出: YES

#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, t;
    cin >> s >> t;
    cout << (s.find(t) != string::npos ? "YES" : "NO") << endl;
    return 0;
}

作业 3统计字符串中的空格数

输入一行字符串,统计其中空格的数量。

样例输入: hello world how are you 样例输出: 4

#include <iostream>
#include <string>
using namespace std;
int main() {
    string s;
    getline(cin, s);
    int cnt = 0;
    for (char c : s) if (c == ' ') cnt++;
    cout << cnt << endl;
    return 0;
}

🔥 拓展习题尖子生挑战7道

挑战 1字符串分割为单词列表

输入一行含空格的句子,输出每个单词(每个单词一行)。

提示:istringstream 或手动遍历判断空格边界。

挑战 2首字母大写

将字符串中每个单词的首字母大写,其余字母小写。

提示: 遍历时遇到空格后的字母 toupper,其余 tolower

挑战 3统计单词频率

输入多行单词,统计每个不同单词出现的次数,按出现次数从多到少排序输出(等同时按字典序)。

提示: 可使用 map<string, int>

挑战 4替换所有目标字符

将字符串中所有大写字母替换为 *,输出结果。

提示: 遍历判断 isupper,替换为 '*'

挑战 5最长公共前缀

给定多个字符串,找出它们的最长公共前缀。

提示: 以第一个字符串为基准,逐字符与其他字符串比较。

挑战 6字符串异位词判断

判断两个字符串是否是字母异位词(相同字母,不同顺序,忽略大小写)。

提示: 统计两个字符串各字母出现次数,比较计数数组是否相同。

挑战 7字符串的字典序最小旋转

将字符串左旋一位(把第一个字符移到末尾),重复 n 次,输出字典序最小的一种。

提示: 枚举所有旋转结果,用 string 比较找最小值。