1. C++ string基础语法精讲
作为C++标准库中最常用的容器之一,string类提供了比C风格字符串(char*)更安全、更便捷的文本操作方式。在GESP三级考试中,string的熟练使用是基础中的基础。我们先从构造函数开始剖析:
cpp复制#include <string>
using namespace std;
// 常用构造方式
string s1; // 空字符串
string s2("Hello"); // 从C风格字符串构造
string s3(5, 'A'); // 填充构造 "AAAAA"
string s4(s2); // 拷贝构造
string的内存管理采用动态分配策略,其底层实现通常包含三个关键成员:
- 字符指针:指向堆内存中的字符数组
- 容量(capacity):当前分配的内存大小
- 长度(size):实际存储的字符数
这种设计使得string能够自动处理内存扩展,当size超过capacity时会触发2倍扩容机制。考试中常考察的成员函数包括:
cpp复制// 容量相关
s.empty(); // 判空
s.size(); // 获取长度
s.capacity(); // 获取容量
s.reserve(100);// 预分配空间
// 元素访问
s[0]; // 不检查越界
s.at(0); // 会抛出out_of_range异常
s.front(); // 首字符
s.back(); // 末字符
// 修改操作
s.append(" world"); // 追加
s.insert(5, " dear");// 插入
s.erase(5, 4); // 删除
s.replace(6, 5, "GESP"); // 替换
重要考点:string的operator[]和at()区别在于边界检查,考试中常设计越界访问的陷阱题
2. string的常用算法与转换
标准库为string提供了丰富的算法支持,这些是GESP三级考试的高频考点:
2.1 子串操作
cpp复制string s = "CCF GESP C++";
string sub1 = s.substr(4, 4); // "GESP"
size_t pos = s.find("C++"); // 返回8
size_t notFound = s.find("Java");// string::npos
find系列方法支持从指定位置开始查找:
- find_first_of:查找任意匹配字符
- find_last_of:反向查找
- find_first_not_of:查找第一个不匹配字符
2.2 字符串分割
考试中常要求实现字符串分割,标准方法如下:
cpp复制vector<string> split(const string& s, char delim) {
vector<string> tokens;
size_t start = 0, end = s.find(delim);
while (end != string::npos) {
tokens.push_back(s.substr(start, end - start));
start = end + 1;
end = s.find(delim, start);
}
tokens.push_back(s.substr(start));
return tokens;
}
2.3 类型转换
数值与字符串的相互转换是常见需求:
cpp复制// 字符串转数字
int num1 = stoi("42");
double num2 = stod("3.14");
// 数字转字符串
string s1 = to_string(123);
string s2 = to_string(3.14159);
易错点:stoi遇到非法字符时会截断转换,如"123abc"会转为123而不报错
3. string与IO操作
3.1 标准IO处理
cpp复制string line;
getline(cin, line); // 读取整行(包含空格)
string word;
cin >> word; // 读取到空白符停止
处理混合输入时的经典模式:
cpp复制int n;
cin >> n;
cin.ignore(); // 清除数字后的换行符
string s;
getline(cin, s);
3.2 文件操作
文件读写中的字符串处理:
cpp复制#include <fstream>
// 读取文件内容到字符串
ifstream fin("input.txt");
string content((istreambuf_iterator<char>(fin)),
istreambuf_iterator<char>());
// 字符串写入文件
ofstream fout("output.txt");
fout << content;
4. 经典例题解析
4.1 字符串反转(GESP样题)
cpp复制string reverseString(string s) {
int left = 0, right = s.size() - 1;
while (left < right) {
swap(s[left++], s[right--]);
}
return s;
}
4.2 验证回文串
考虑大小写和标点的情况:
cpp复制bool isPalindrome(string s) {
string filtered;
for (char c : s) {
if (isalnum(c)) {
filtered += tolower(c);
}
}
return filtered == reverseString(filtered);
}
4.3 字符串压缩
统计连续字符出现次数:
cpp复制string compress(string s) {
string res;
int count = 1;
for (int i = 1; i <= s.size(); ++i) {
if (i < s.size() && s[i] == s[i-1]) {
count++;
} else {
res += s[i-1];
if (count > 1) res += to_string(count);
count = 1;
}
}
return res.size() < s.size() ? res : s;
}
4.4 最长公共前缀
纵向扫描法:
cpp复制string longestCommonPrefix(vector<string>& strs) {
if (strs.empty()) return "";
for (int i = 0; i < strs[0].size(); ++i) {
char c = strs[0][i];
for (int j = 1; j < strs.size(); ++j) {
if (i == strs[j].size() || strs[j][i] != c) {
return strs[0].substr(0, i);
}
}
}
return strs[0];
}
5. 性能优化与常见陷阱
5.1 避免不必要的拷贝
cpp复制// 低效写法
string process(string s) {
string temp = s; // 不必要的拷贝
// 处理temp...
return temp;
}
// 高效写法
string process(const string& s) { // 传引用
string temp = s; // 确实需要拷贝时再复制
// 处理temp...
return temp;
}
5.2 预留空间优化
当预先知道字符串大小时:
cpp复制string result;
result.reserve(1000); // 避免多次扩容
for (int i = 0; i < 1000; ++i) {
result += 'a';
}
5.3 常见错误排查
- 越界访问:
cpp复制string s = "hello";
char c = s[5]; // 未定义行为
- 迭代器失效:
cpp复制string s = "test";
auto it = s.begin();
s += "ing"; // 可能导致it失效
// cout << *it; // 危险!
- C风格字符串转换:
cpp复制string s = "123";
printf("%s", s); // 错误!
printf("%s", s.c_str()); // 正确
6. 实战技巧与考试策略
6.1 字符串匹配优化
KMP算法是高效字符串匹配的经典方案:
cpp复制vector<int> buildNext(const string& pattern) {
vector<int> next(pattern.size());
int j = 0;
for (int i = 1; i < pattern.size(); ) {
if (pattern[i] == pattern[j]) {
next[i++] = ++j;
} else if (j > 0) {
j = next[j-1];
} else {
next[i++] = 0;
}
}
return next;
}
int kmpSearch(const string& text, const string& pattern) {
auto next = buildNext(pattern);
int j = 0;
for (int i = 0; i < text.size(); ) {
if (text[i] == pattern[j]) {
i++; j++;
if (j == pattern.size()) return i - j;
} else if (j > 0) {
j = next[j-1];
} else {
i++;
}
}
return -1;
}
6.2 正则表达式基础
C++11引入的regex库:
cpp复制#include <regex>
// 验证邮箱格式
bool isValidEmail(const string& email) {
regex pattern(R"(\w+@\w+\.\w+)");
return regex_match(email, pattern);
}
// 提取所有数字
vector<string> extractNumbers(const string& s) {
regex number(R"(\d+)");
sregex_iterator it(s.begin(), s.end(), number);
sregex_iterator end;
vector<string> numbers;
while (it != end) {
numbers.push_back(it->str());
++it;
}
return numbers;
}
6.3 考试时间分配建议
-
基础语法题:5-8分钟/题
- 重点检查边界条件
- 注意string与数值的转换陷阱
-
算法实现题:15-20分钟/题
- 先写伪代码理清思路
- 优先实现暴力解法,再考虑优化
-
调试技巧:
- 使用cout输出中间结果
- 构造边界测试用例(空串、长串等)
7. 模拟试题与详解
7.1 字符串解码(GESP三级真题)
题目:实现字符串解码,如"3[a]2[bc]"解码为"aaabcbc"
cpp复制string decodeString(string s) {
stack<int> nums;
stack<string> strs;
string curr;
int num = 0;
for (char c : s) {
if (isdigit(c)) {
num = num * 10 + (c - '0');
} else if (isalpha(c)) {
curr += c;
} else if (c == '[') {
nums.push(num);
strs.push(curr);
num = 0;
curr.clear();
} else if (c == ']') {
int repeat = nums.top(); nums.pop();
string temp = strs.top(); strs.pop();
for (int i = 0; i < repeat; ++i) {
temp += curr;
}
curr = temp;
}
}
return curr;
}
7.2 字符串排列(GESP三级模拟题)
判断s2是否包含s1的排列:
cpp复制bool checkInclusion(string s1, string s2) {
vector<int> target(26), window(26);
for (char c : s1) target[c-'a']++;
for (int i = 0; i < s2.size(); ++i) {
window[s2[i]-'a']++;
if (i >= s1.size()) {
window[s2[i-s1.size()]-'a']--;
}
if (window == target) return true;
}
return false;
}
7.3 字符串相乘(大数乘法)
实现大数乘法字符串表示:
cpp复制string multiply(string num1, string num2) {
int m = num1.size(), n = num2.size();
vector<int> res(m + n);
for (int i = m - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
int mul = (num1[i] - '0') * (num2[j] - '0');
int sum = mul + res[i + j + 1];
res[i + j] += sum / 10;
res[i + j + 1] = sum % 10;
}
}
string ans;
for (int num : res) {
if (!(ans.empty() && num == 0)) {
ans += to_string(num);
}
}
return ans.empty() ? "0" : ans;
}
8. 资源推荐与进阶学习
8.1 官方文档参考
-
C++标准库string文档:
- cppreference.com
- 重点关注:构造函数、容量操作、修改操作、查找操作
-
GESP考试大纲:
- 三级要求熟练掌握string的基本操作
- 四级以上要求掌握字符串匹配算法
8.2 推荐练习平台
- 洛谷:字符串基础题库
- LeetCode:String标签下的经典题目
- Codeforces:Div.2竞赛中的字符串问题
8.3 调试技巧
- VS Code调试配置:
json复制{
"version": "0.2.0",
"configurations": [
{
"name": "G++ Debug",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++ build active file"
}
]
}
- 常用调试打印技巧:
cpp复制#define debug(x) cerr << #x << " = " << x << endl
string s = "debug me";
debug(s); // 输出:s = debug me
在实际教学中发现,学生最容易在以下场景出错:
- 混淆size()和length()(其实完全等价)
- 忘记字符串下标从0开始
- 处理混合输入时未清除缓冲区
- 未考虑空字符串的特殊情况
建议在考试前重点练习这些易错点,每个string操作都问问自己:如果字符串为空会怎样?如果索引越界会怎样?养成防御性编程的习惯能有效避免失分
