7 string字符串及其函数(一)

正在加载视频播放器…

GESP C++ 三级:string 字符串及其函数

核心目标:掌握 string 类型的定义、初始化、输入输出,熟练使用 size/length、substr、find、insert、erase、replace、append 等核心函数,理解 string 与 char 数组的区别,能综合运用字符串函数配合枚举法和模拟法解决实际问题。
string 是会自动管理内存的字符串类型;下标从 0 开始,find 找不到返回 string::npos,substr(pos, len) 从 pos 开始截取 len 个字符;遍历前先确认下标范围,空字符串和单字符必须单独验证。

一、string 的定义与初始化

需要包含头文件:

#include <string>
using namespace std;

多种创建方式:

string s1;                  // 空字符串 ""
string s2("Hello GESP");    // 直接初始化
string s3(s2);              // 拷贝初始化
string s4(5, 'A');          // 重复字符 "AAAAA"
string s5 = "C++三级";       // 赋值初始化

输入输出:

string s;
cin >> s;          // 读入一个单词(遇到空格停止)
getline(cin, s);   // 读入一整行(包括空格)
cout << s << endl; // 输出字符串

重点:cin >> s 遇到空格就停止,如果题目要求读入含空格的字符串,必须使用 getline(cin, s)。

二、string 核心函数详解

1. 长度与判空

string s = "GESP";
cout << s.size() << endl;    // 4
cout << s.length() << endl;  // 4,与 size() 功能相同
cout << s.empty() << endl;   // 0(false),不为空返回 0
  • s.size() 和 s.length() 功能相同,返回字符个数(不含结束符)。
  • s.empty() 返回 bool,空字符串返回 true。

2. 访问与遍历

string s = "GESP";
cout << s[0] << endl;       // 'G',下标从0开始
cout << s.at(1) << endl;    // 'E',at()会检查越界
cout << s.front() << endl;  // 'G',首字符
cout << s.back() << endl;   // 'P',末字符

遍历方式:

// 方式1:下标遍历(最常用)
for (int i = 0; i < s.size(); i++) {
    cout << s[i] << " ";
}

// 方式2:范围for循环
for (char c : s) {
    cout << c << " ";
}

3. 查找 find

string s = "CCF GESP C++";
size_t pos = s.find("GESP");     // 返回 4
size_t pos2 = s.find("C++");     // 返回 9
size_t pos3 = s.find("Java");    // 返回 string::npos
  • s.find(sub, pos):从 pos 位置开始查找子串 sub,找到返回起始下标,未找到返回 string::npos。
  • string::npos 是一个特殊常量,表示“未找到”。

判断是否找到:

if (s.find("GESP") != string::npos) {
    cout << "找到了" << endl;
} else {
    cout << "没找到" << endl;
}

4. 截取子串 substr

string s = "CCF GESP C++";
string sub1 = s.substr(4, 4);    // "GESP",从下标4开始取4个字符
string sub2 = s.substr(9);       // "C++",从下标9开始取到末尾
  • s.substr(pos, len):从 pos 开始截取长度为 len 的子串;若省略 len 则截取到末尾。

5. 插入、删除与替换

string str = "GESP考试";
str.insert(4, " C++");       // 在位置4插入,结果 "GESP C++考试"
str.erase(8, 2);             // 从位置8开始删除2个字符,结果 "GESP C++"
str.replace(5, 3, "三级");   // 从位置5开始替换3个字符为"三级"
str.append(" 考试");          // 在末尾追加,结果 "GESP C++三级 考试"
str.push_back('!');          // 在末尾追加一个字符
str.pop_back();              // 删除末尾一个字符
str.clear();                 // 清空字符串
  • s.insert(pos, str):在位置 pos 插入字符串 str。
  • s.erase(pos, len):从 pos 开始删除 len 个字符。
  • s.replace(pos, len, str):从 pos 开始删除 len 个字符,并插入字符串 str。
  • s.append(str):在末尾追加字符串。
  • s.push_back(c):在末尾追加一个字符。
  • s.pop_back():删除末尾一个字符。

6. 字符串拼接

string s1 = "GESP";
string s2 = "C++";
s1 += " ";           // 拼接空格
s1 += s2;            // 拼接字符串
s1.append(" 三级");   // 使用append
// 结果:"GESP C++ 三级"

7. 字符串比较

string a = "abc";
string b = "abd";
if (a == b) cout << "相等";       // 直接使用 == 比较
if (a < b) cout << "a < b";      // 按字典序比较

8. 类型转换

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

// 数字转字符串
string s1 = to_string(123);
string s2 = to_string(3.14);

三、字符处理辅助函数

配合字符串遍历使用,需包含头文件 <cctype>:

函数 功能 示例
isupper(c) 是否大写字母 isupper('A') 为真
islower(c) 是否小写字母 islower('a') 为真
isdigit(c) 是否数字字符 isdigit('7') 为真
isalpha(c) 是否字母 isalpha('A') 为真
toupper(c) 转大写 toupper('a') 返回 'A'
tolower(c) 转小写 tolower('A') 返回 'a'

示例:统计字符串中大写字母、小写字母和数字的个数

string s;
getline(cin, s);
int upper = 0, lower = 0, digit = 0;

for (char c : s) {
    if (isupper(c)) upper++;
    else if (islower(c)) lower++;
    else if (isdigit(c)) digit++;
}

cout << upper << " " << lower << " " << digit << endl;

四、GESP 三级字符串真题精讲

真题1:字母求和

题目描述:

小杨同学发明了一种新型密码,对于每一个小写英文字母,该小写字母代表了一个正整数,即该字母在字母顺序中的位置,例如字母 a 代表了正整数 1,字母 b 代表了正整数 2;对于每一个大写英文字母,该大写字母代表了一个负整数,即该字母的 ASCII 码的相反数,例如字母 A 代表了负整数 -65。给定一个字符串,计算它对应的加密前的整数。

解题思路:

遍历字符串,根据字符类型(大小写)进行不同的数值映射并求和。

#include <iostream>
#include <string>
using namespace std;

int main() {
    int n;
    string s;
    cin >> n >> s;
    int sum = 0;
    for (char c : s) {
        if (c >= 'a' && c <= 'z') {
            // 小写字母:字母位置值(a=1, b=2, ...)
            sum += (c - 'a' + 1);
        } else if (c >= 'A' && c <= 'Z') {
            // 大写字母:ASCII码的相反数
            sum -= c;   // 等价于 sum += (-c)
        }
    }
    cout << sum << endl;
    return 0;
}

核心考点:字符遍历 + 字符类型判断 + ASCII 码运算。

真题2:分割字符串

题目描述:

小明拿到了一段字符串文本,按规则分割:从左到右扫描,第一次遇到1个空格时分割为左右两部分(舍弃空格);对右侧字符串继续扫描,第一次遇到连续2个空格时分割(舍弃这2个空格);下一次需要连续3个空格,以此类推。输出每次分割左侧的字符串,以及最后一次分割的右侧字符串。如果完全无法分割,直接输出原字符串。

解题思路:

这道题是 find 和 substr 的典型应用。核心是用循环逐步查找“连续n个空格”的位置,分割字符串。

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    getline(cin, s);

    int need = 1;          // 本次需要连续几个空格
    int start = 0;         // 当前处理的起始位置
    bool split = false;    // 是否进行过分割

    while (true) {
        // 构造 need 个连续空格的查找目标
        string target(need, ' ');

        // 从 start 位置开始查找
        size_t pos = s.find(target, start);

        if (pos == string::npos) {
            // 找不到,无法继续分割
            if (!split) {
                cout << s << endl;   // 完全无法分割,输出原字符串
            } else {
                cout << s.substr(start) << endl;  // 输出最后一部分
            }
            break;
        }

        // 输出分割左侧的部分
        cout << s.substr(start, pos - start) << endl;
        split = true;

        // 更新起始位置(跳过分割用的空格)
        start = pos + need;
        need++;   // 下次需要更多空格
    }

    return 0;
}

关键细节:

细节 说明
s.find(target, start) 从 start 开始查找目标子串
s.substr(start, pos - start) 截取左侧部分
s.substr(start) 截取从 start 到末尾的部分
getline(cin, s) 输入可能包含空格,必须用 getline
split 标志 记录是否进行过分割,区分输出逻辑
空行输出 如果分割出空字符串,必须输出空行(不能省略)

真题3:密码合规检测

题目描述:

检查密码有效性,合规密码应满足:① 只能由大小写字母、数字和 !@#$ 组成;② 长度 6~12;③ 大写字母、小写字母和数字至少包含其中两种,且至少包含 !@#$ 中的一个。

解题思路:

多重条件验证,遍历字符串统计各类字符数量,逐一判断规则。

#include <iostream>
#include <string>
using namespace std;

bool isValid(string pwd) {
    if (pwd.size() < 6 || pwd.size() > 12) return false;

    int upper = 0, lower = 0, digit = 0, special = 0;
    for (char c : pwd) {
        if (c >= 'a' && c <= 'z') lower++;
        else if (c >= 'A' && c <= 'Z') upper++;
        else if (c >= '0' && c <= '9') digit++;
        else if (c == '!' || c == '@' || c == '#' || c == '$') special++;
        else return false;   // 含非法字符
    }

    // 至少包含两种:大小写字母和数字
    int types = 0;
    if (upper > 0) types++;
    if (lower > 0) types++;
    if (digit > 0) types++;

    return types >= 2 && special >= 1;
}

核心考点:字符遍历 + 多条件统计 + 规则验证。

五、易错点

1. 空字符串和单字符字符串(近场考试最高频陷阱)

空字符串和单字符字符串这两个极端场景,必须单独写代码验证,绝对不能让循环从 i=0 开始直接覆盖所有情况,这是近3场考试里 60% 考生丢分的高频陷阱。

// 错误写法:假设字符串长度至少为2
for (int i = 0; i < s.size() - 1; i++) { ... }
// 如果 s 为空,s.size() - 1 会变成很大的数(size_t 无符号),导致越界!

// 正确写法:先检查长度
if (s.empty()) { cout << "空字符串"; return 0; }
for (int i = 0; i + 1 < (int)s.size(); i++) { ... }

2. 下标越界

写代码前先在草稿纸上把字符串的每个字符标上从 0 开始的下标,确认遍历范围完全正确后再写循环,这类错误占编程题失分的 40% 以上。

string s = "GESP";   // 有效下标:0, 1, 2, 3
// s[4] 是越界访问!

3. size() 返回无符号整数

string s;
// ❌ 错误:s.size() 是 size_t,无符号整数,s.size() - 1 可能溢出
for (int i = 0; i < s.size() - 1; i++) { ... }

// ✅ 正确:强制转为 int
for (int i = 0; i + 1 < (int)s.size(); i++) { ... }

4. find 找不到时返回 string::npos

// ❌ 错误:不能用 -1 判断
if (s.find("abc") == -1) { ... }

// ✅ 正确:用 string::npos
if (s.find("abc") == string::npos) { ... }

5. cin >> s 遇到空格停止

string s;
cin >> s;           // 输入 "Hello World",s 只得到 "Hello"
getline(cin, s);    // 正确,读入整行 "Hello World"

6. substr 参数含义

string s = "GESP C++";
s.substr(5, 3);    // 从下标5开始,取3个字符,返回 "C++"
s.substr(5);       // 从下标5开始,取到末尾,返回 "C++"

第一个参数是起始下标,第二个参数是截取长度,不是结束下标。

7. 字符统计用数组提速

所有字符统计类题目,优先用 int cnt[256] 的数组直接计数,不用嵌套循环逐个比对,时间复杂度直接从 O(n²) 降到 O(n),彻底避免超时。

int cnt[256] = {0};
for (char c : s) {
    cnt[(int)c]++;
}
// cnt['a'] 就是字符 'a' 出现的次数

六、速查表

需求 写法 说明
定义字符串 string s = "Hello"; 需 <string>
读入一行 getline(cin, s); 含空格
长度 s.size() 或 s.length() 返回字符个数
判空 s.empty() 空返回 true
访问字符 s[i] 或 s.at(i) 下标从0开始
首/末字符 s.front() / s.back()
查找 s.find(sub, pos) 找不到返回 string::npos
截取子串 s.substr(pos, len) 省略 len 取到末尾
插入 s.insert(pos, str)
删除 s.erase(pos, len)
替换 s.replace(pos, len, str)
追加 s.append(str) / s += str
末尾加字符 s.push_back(c)
末尾删字符 s.pop_back()
清空 s.clear()
字符串转数字 stoi(s) / stod(s)
数字转字符串 to_string(n)
判断大写 isupper(c) 需 <cctype>
判断小写 islower(c)
判断数字 isdigit(c)
转大写 toupper(c)
转小写 tolower(c)

七、总结

string 字符串及其函数是 GESP 三级考试的核心模块,分值占比 15%-20%。

  1. string 自动管理内存,比 char 数组更安全、更便捷。
  2. size() 和 length() 功能相同,返回字符个数(不含结束符)。
  3. cin >> s 遇到空格停止,读整行用 getline(cin, s)。
  4. find 找不到返回 string::npos,不能用 -1 判断。
  5. substr(pos, len) 第一个参数是起始下标,第二个是截取长度。
  6. insert 插入、erase 删除、replace 替换,参数含义要记牢。
  7. 遍历前先在草稿纸上标好下标,避免越界。
  8. 空字符串和单字符字符串必须单独验证,这是近场考试最高频陷阱。
  9. size() 返回无符号整数,与 int 比较时要强制转换。
  10. 字符统计优先用 int cnt[256] 数组,O(n) 效率不超时。

复习建议:先掌握 find、substr、getline 三个最常考的函数,再练习“字母求和”“密码合规检测”两类真题,最后挑战“分割字符串”这类综合题。每道题写完必须用空字符串、单字符字符串、含空格字符串三组边界数据手动验证。考试中先读懂题目规则,确定需要哪些字符串函数,再写遍历和判断逻辑,最后逐行检查下标和边界。