InfoCode

C++ · 字符串

字符串 string 及其函数

追踪cin读数字后残留的换行,正确用getline读取带空格的一整行;保留字符统计、回文、查找和截取示例。

InfoCode 编写 · 技术参考见下文

在应用中练这个知识点 在应用中阅读讲解

string 的访问与常用操作

可以把字符串想象成一列火车:每节车厢装一个字母,下标从 0 开始编号。s[0] 是第一节,s[1] 是第二节……

C++ 里有两种常用方式:

复试常考:统计字符、翻转字符串、判断回文、查找子串、字符大小写转换。

常见成员函数: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\nn = 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 是要替换的字符数。

提示

先修知识

技术参考

范围说明

本站讲解由 InfoCode 编写,不是官方考纲;参考级别是本站映射,不代表官方等级、认证或参赛资格。练习记录不等于掌握或资格。

参考级别:GESP 3 级(本站映射)

查看赛事关系与路径