C++ · 字符串
字符串 string 及其函数
追踪cin读数字后残留的换行,正确用getline读取带空格的一整行;保留字符统计、回文、查找和截取示例。
string 的访问与常用操作
可以把字符串想象成一列火车:每节车厢装一个字母,下标从 0 开始编号。s[0] 是第一节,s[1] 是第二节……
C++ 里有两种常用方式:
char s[100]:老式字符数组,末尾有'\0'结束符,用strlen/strcmp/strcpy等函数操作。string s:更方便,支持+拼接、s.length()求长、s.substr()取子串、s.find()查找。
复试常考:统计字符、翻转字符串、判断回文、查找子串、字符大小写转换。
常见成员函数:size()/length() 返回长度,empty() 判断空串;substr(pos,len) 取子串,find 返回位置或 string::npos;insert(pos,text) 插入,erase(pos,len) 删除,replace(pos,len,text) 替换。pos 要合法,len 是长度而不是结束下标。读取含空格的一整行用 getline;若之前读过数字,先处理残留换行。
cin后接getline,输入流里还剩什么?
cin >> name 读取一个词,遇到空白停止;getline(cin, name) 默认读取到换行,保留行内空格并取走换行。假定输入协议是“第一行整数,下一行完整姓名”,输入为 3\nAda Lovelace\n;这里\n表示换行字符。
| 操作 | 剩余输入 | 得到的内容 |
|---|---|---|
| 开始 | 3\nAda Lovelace\n | 尚未读取 |
| cin >> n | \nAda Lovelace\n | n = 3 |
| 丢弃第一行剩余内容(含换行) | Ada Lovelace\n | 姓名仍未读取 |
| getline(cin, name) | 空 | name = "Ada Lovelace" |
若在读完数字后直接getline,它立即遇到残留换行,得到空串;这不是程序自动跳过了下一行。对这里的输入协议,成功读数后用 cin.ignore(numeric_limits<streamsize>::max(), '\n') 丢弃当前行剩余内容,再读姓名。它会丢弃当前行的其他字符,因此不适用于“数字和姓名在同一行”的格式。
常见错误一:无条件调用两次getline,可能吞掉本来要保留的一行。错误二:把 getline(cin >> ws, name) 当作通用修复;ws会跳过所有前导空白,包括空行和姓名开头的空格。需要保留这些内容时,按输入格式处理当前行的换行即可。下面假定数字读取成功,并检查实际读取结果;失败恢复另行处理。读取长度k的文本要处理相应字符,不能写成固定O(1)。
运行验证:读完数字再读整行
#include <iostream>
#include <limits>
#include <string>
int main() {
int n;
std::string name;
if (!(std::cin >> n)) { return 0; }
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (!std::getline(std::cin, name)) { return 0; }
std::cout << n << " [" << name << "]\n";
}输入两行:3和Ada Lovelace,输出3 [Ada Lovelace]。方括号帮助看见空串和保留的空格。
先自己判断,再展开答案
第一行是3后面两个空格再换行,ignore到换行还有效吗?
有效,当前行剩下的空格和换行都会被丢弃。只ignore一个字符则可能留下其他空白。
下一行是两个空格加Ada,示例会保留开头两个空格吗?
会,getline读取下一行时不跳过前导空格。用ws预先跳过空白则会丢掉它们。
姓名和数字在同一行,如3 Ada Lovelace,能直接沿用这里的ignore吗?
不能,它会把姓名也丢弃。先说明输入格式,再决定如何读取剩余文本。
字符统计、回文与字符串修改
例1:统计字符串中每种字母出现次数
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Hello World";
int cnt[26] = {0};
for (char c : s) {
if (c >= 'a' && c <= 'z') cnt[c - 'a']++;
if (c >= 'A' && c <= 'Z') cnt[c - 'A']++;
}
for (int i = 0; i < 26; i++) {
if (cnt[i] > 0)
cout << (char)('a' + i) << ": " << cnt[i] << endl;
}
return 0;
}用 c-'a' 把字母转成 0~25 的下标存入数组,最后遍历输出。"Hello World" 中 d:1 e:1 h:1 l:3 o:2 r:1 w:1。
例2:判断字符串是否是回文
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.length();
bool ok = true;
for (int i = 0; i < n / 2; i++) {
if (s[i] != s[n - 1 - i]) {
ok = false;
break;
}
}
cout << (ok ? "YES" : "NO") << endl;
return 0;
}输入 "racecar",n=7,比较 s[0] 和 s[6],s[1] 和 s[5],s[2] 和 s[4],全部相等,输出 YES。
例3:查找、截取、插入与删除
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "hello world";
auto pos = s.find("world");
if (pos != string::npos) s.replace(pos, 5, "C++");
s.insert(0, "Hi! "); s.erase(0, 4);
cout << s << " " << s.substr(0, 5) << endl;
}输出 hello C++ hello。find 成功后才使用位置;replace 的 5 是要替换的字符数。
提示
- string 的下标从 0 开始,最后一个字符下标是 s.length()-1,越界访问会出错。
- 字符和整数可以互相转换:'a'+1 就是 'b','A' 和 'a' 差 32(可用 tolower/toupper 转换大小写)。
- cin >> s 遇到空格就停止;要读含空格的整行用 getline(cin, s)。
- s.find("abc") 找不到时返回 string::npos,要判断是否为这个特殊值来确认是否找到。
先修知识
技术参考
范围说明
本站讲解由 InfoCode 编写,不是官方考纲;参考级别是本站映射,不代表官方等级、认证或参赛资格。练习记录不等于掌握或资格。
参考级别:GESP 3 级(本站映射)