这一章《字符类型和字符数组》是信奥赛的基石。在 CSP-J/S 中,字符串处理(模拟、解析、加密)是必考题型。
🚀 C++ 信奥赛笔记:字符串
🌟 第一课:char与string
1. 什么是字符?
如果把一句话比作一串糖葫芦,那么每一颗山楂就是一个字符(char)。
- 定义:
char c = 'A';(注意:必须用单引号' '包裹,且只能放一个东西) - ASCII 码的秘密: 计算机里,字符其实是数字!
'A'是 65,'a'是 97,'0'是 48。- 口诀: 小写比大写大 32(
'a' - 'A' = 32)。 - 应用: 【例5.15】替换字母、【例5.18】串排序都要用到这个规律。
2. 两种武器:数组 vs string
- 老式武器
char s[100]: 像一排固定的格子,操作快但容易越界(比如 P1098 这种老题)。 - 新式武器
string s: 像橡皮筋,能长能短,自带很多功能(推荐初学者用这个)。
🛠️ 第二课:基本功训练(必会操作)
1. 怎么读入一整行?
孩子最容易踩的坑:cin 遇到空格就停了!
- 场景: 【例5.16】过滤空格、【例5.19】字符串判等。
- 神器:
getline(cin, s);- 它可以读入包含空格的整行文字。
- 注意: 如果前面用了
cin >> n;,后面接getline,中间要加一句getchar();吃掉回车键!
2. 怎么知道有多长?
s.length()或s.size()。- 应用: 遍历字符串时,循环条件写
i < s.length()。
3. 大小写转换魔法
- 题目: 【例5.15】替换字母、P1138 将字符串中的小写字母转换成大写字母。
- 代码公式:
- 变大写:
c = c - 32; - 变小写:
c = c + 32; - 判断是不是字母:
if (c >= 'a' && c <= 'z')
- 变大写:
⚔️ 第三课:实战演练(结合一本通题目)
将题目分为三个等级
🟢 青铜级:单字符操作
目标: 熟悉 ASCII 码和循环遍历。
- 【例5.15】替换字母
- 思路: 遍历每一个字符,如果是 'A' 就改成 'E'。
- 考点:
if(s[i] == 'A') s[i] = 'E';
- P1138 将字符串中的小写字母转换成大写字母
- 思路: 遍历,如果是小写(
>= 'a'),就减去 32。
- 思路: 遍历,如果是小写(
- P1146 判断字符串是否为回文
- 思路: "回文"就是正着读反着读一样(如
abcba)。 - 技巧: 用两个指针,一个从头
i=0,一个从尾j=len-1,向中间靠拢比较。
- 思路: "回文"就是正着读反着读一样(如
🟡 白银级:子串与查找
目标: 学会"切片"和"搜索"。
- 【例5.20】字串包含
- 问题: 字符串 A 里面有没有字符串 B?
- 神器函数:
s.find("abc")。如果返回值不是string::npos,说明找到了!
- P1140 验证子串
- 同上: 练习
find函数的使用。
- 同上: 练习
- P1141 删除单词后缀
- 思路: 看看最后几个字符是不是 "ing", "ly", "er"。如果是,就把它们切掉(
s.erase(...)或s.substr(...))。
- 思路: 看看最后几个字符是不是 "ing", "ly", "er"。如果是,就把它们切掉(
- P1142 单词的长度
- 思路: 找空格!遇到空格说明一个单词结束了,统计长度并重置计数器。
🔴 黄金级:综合应用与逻辑
目标: 结合数学逻辑或复杂规则。
- 【例5.18】串排序
- 难点: 字典序排序(先比第一个字母,一样再比第二个...)。
- 解法: 直接用
sort(v.begin(), v.end())对vector<string>排序,C++ 默认就是字典序!
- P1132 基因相关性
- 思路: 这是一个统计题。遍历两个字符串,数一数有多少个位置字符相同,算出比例。
- P1136 配对碱基链
- 思路: 映射关系。A-T, G-C。遍历字符串,用
if-else或者switch进行转换输出。
- 思路: 映射关系。A-T, G-C。遍历字符串,用
- P1145 字符串p型编码
- 思路: 游程编码(RLE)。比如
aaabbc->3a2b1c。需要记录当前字符和它连续出现的次数。
- 思路: 游程编码(RLE)。比如
💡 小贴士(避坑指南)
- 关于
char数组的结束符\0:- C 风格字符串最后藏着一个看不见的"小尾巴"
\0。所以定义数组时,长度要比实际文字多 1。例如存 "Hi" 需要char s[3]。
- C 风格字符串最后藏着一个看不见的"小尾巴"
- 关于下标越界:
- 字符串长度是
len,最后一个字符的下标是len-1。这是新手最容易报错的地方(Runtime Error)。
- 字符串长度是
- 关于调试:
- 在循环里打印
i和s[i],看看程序到底在读什么,这比干瞪眼有效得多。
- 在循环里打印
📝 课后作业清单(建议顺序)
- P1138 大小写转换(热身)
- P1146 回文串判断(经典逻辑)
- P1140 验证子串(学习 find)
- P1141 删除后缀(学习 substr/erase)
- P1132 基因相关性(综合统计)
- P1145 p型编码(挑战题)
C++ 字符串教学内容和常见操作方法可归纳为两大体系:C 风格字符数组与标准库 std::string,其中后者是信奥赛和工程实践中的主流选择。建议以 string 为主线,辅以字符数组基础概念
一、注意点
-
字符与字符串的本质
- 字符是单个符号(如
'A'、'1'),用单引号包裹;字符串是字符序列,用双引号包裹。 - 计算机中字符本质是数字(ASCII 码),例如
'A' = 65,'a' = 97,小写比大写大 32。这是大小写转换、字母排序等题目的底层逻辑。
- 字符是单个符号(如
-
两种字符串表示法
- C 风格字符数组:
char s[100] = "Hello";,以\0结尾,需手动管理长度和边界,适合理解底层原理。 std::string:string s = "Hello";,自动管理内存,支持动态扩容,内置丰富方法,是竞赛首选。
- C 风格字符数组:
-
输入输出陷阱
cin >> s遇到空格/换行即停止,适用于单单词输入。getline(cin, s)可读取整行含空格的文本,但若前文有cin >> n,需加getchar()吃掉残留换行符,否则getline会读入空行。
-
常用操作方法
- 基础属性 :
s.length()或s.size()获取长度;s.empty()判断是否为空。 - 访问与修改 :
s[i]或s.at(i)访问第 i 个字符(从 0 开始);s.push_back('x')尾部追加字符;s.insert(pos, "abc")在位置 pos 插入子串。 - 拼接与替换 :
s1 + s2或s1.append(s2)拼接;s.replace(start, len, "new")替换从 start 开始、长度为 len 的子串。 - 查找与截取 :
s.find("abc")返回子串首次出现位置(未找到返回string::npos);s.substr(start, len)提取子串。 - 比较与清空 :
s1 == s2直接比较内容;s.clear()清空字符串。
- 基础属性 :
-
高频考点题型
- 大小写转换 :遍历字符串,若字符在
'a'-'z'范围,则减去 32 转为大写。 - 回文判断:首尾双指针向中间逼近,比较对应字符是否相等。
- 子串匹配 :用
find()或手动滑动窗口实现。 - 词频统计 :结合
map<string, int>统计每个单词出现次数。 - 加密解密:如凯撒密码,对每个字符按固定偏移量变换。
- 大小写转换 :遍历字符串,若字符在
二、避坑指南
- 避免过早引入指针 :无需理解
char*,聚焦string即可。 - 警惕越界访问 :强调
s[i]的 i 必须小于s.length(),否则行为未定义。 - 慎用
c_str():仅在调用 C 风格函数(如printf)时才需转换,日常操作用string原生方法。 - 注意
find()返回值 :未找到时返回string::npos(通常为-1或极大值),不可直接与0比较。
找我领一份「学生速查表」~