@鞠大龙 魅客科创中心
string类的本质:
基本使用:
#include <string> using namespace std; string s1; // 空字符串 string s2 = "Hello"; // 用字符串字面量初始化 string s3(5, 'a'); // "aaaaa" string s4 = s2; // 拷贝构造
优点:
内存管理:
string s = "Hello"; s += " World"; // 自动扩容 s.clear(); // 自动释放
与字符数组对比:
// 字符数组 char str1[100]; // 固定长度 strcpy(str1, "Hello"); // 需要手动复制 strcat(str1, " World");// 可能溢出 // string类 string str2 = "Hello"; // 自动管理长度 str2 += " World"; // 安全的拼接
// 常见的初始化方式 string s1; // 默认构造,空字符串 string s2 = "Hello"; // 字符串字面量 string s3("World"); // 构造函数形式 string s4(5, '*'); // 重复字符:"*****" string s5 = s2; // 拷贝构造 string s6 = s2 + " " + s3; // 表达式初始化 // 从字符数组构造 char arr[] = "Hello"; string s7(arr); // 从C风格字符串构造 string s8(arr, 3); // 取前3个字符:"Hel" string s9(arr + 1, arr + 4); // 取下标范围[1,4):"ell"
string str = "Hello"; // 访问单个字符 char c1 = str[0]; // 使用[]操作符:'H' char c2 = str.at(1); // 使用at()方法:'e' // 修改单个字符 str[0] = 'h'; // 使用[]修改 str.at(1) = 'E'; // 使用at()修改 // 获取长度 int len1 = str.length(); // 5 int len2 = str.size(); // 5(与length()相同) bool empty = str.empty(); // false // 修改整个字符串 str.assign("World"); // 替换整个字符串 str.clear(); // 清空字符串
字符串拼接:
string s1 = "Hello"; string s2 = "World"; // 使用+运算符 string s3 = s1 + " " + s2; // 使用append方法 s1.append(" "); // 追加字符串 s1.append(s2); // 追加另一个string s1.append(3, '!'); // 追加3个感叹号 // 使用+=运算符 s1 += " "; s1 += s2; s1 += '!';
字符串插入:
string str = "Hello"; // 在指定位置插入 str.insert(5, " "); // "Hello " str.insert(6, "World");// "Hello World" // 插入重复字符 str.insert(5, 3, '-'); // "Hello---World" // 插入其他string对象 string s = "C++"; str.insert(6, s); // "Hello-C++--World"
string str = "Hello World Hello"; // 查找子串 size_t pos1 = str.find("Hello"); // 返回0 size_t pos2 = str.find("Hello", 1); // 返回12(从位置1开始找) size_t pos3 = str.find("C++"); // 返回string::npos(未找到) // 替换子串 str.replace(0, 5, "Hi"); // "Hi World Hello" str.replace(str.find("Hello"), 5, "Bye"); // "Hi World Bye" // 从右向左查找 size_t pos4 = str.rfind("Hello"); // 返回12 // 查找字符集合 size_t pos5 = str.find_first_of("aeiou"); // 返回第一个元音字母的位置 size_t pos6 = str.find_last_of("aeiou"); // 返回最后一个元音字母的位置
子串提取:
string str = "Hello World"; // 使用substr提取子串 string sub1 = str.substr(6); // "World" string sub2 = str.substr(0, 5); // "Hello" string sub3 = str.substr(6, 3); // "Wor" // 常见应用 string filename = "test.cpp"; string name = filename.substr(0, filename.find('.')); // "test" string ext = filename.substr( filename.find('.') + 1); // "cpp"
字符串比较:
string s1 = "Hello"; string s2 = "World"; // 使用比较运算符 bool b1 = s1 == s2; // false bool b2 = s1 < s2; // true bool b3 = s1 >= s2; // false // 使用compare方法 int cmp1 = s1.compare(s2); // <0 int cmp2 = s1.compare("Hello");// =0 int cmp3 = s1.compare(0, 2, "Help", 0, 2); // =0
// 字符数组转string char arr[] = "Hello World"; string s1(arr); // 构造函数 string s2 = arr; // 赋值运算符 string s3(arr, 5); // 只取前5个字符 string s4(arr + 6, arr + 11); // 取下标范围[6,11) // string转字符数组 string str = "Hello World"; const char* c1 = str.c_str(); // 返回C风格字符串 const char* c2 = str.data(); // 类似c_str() // 注意:c_str()和data()返回的是临时指针 // 如果需要持久保存,应该复制到自己的缓冲区 char buffer[100]; strcpy(buffer, str.c_str());
内存管理注意事项:
string str = "Hello"; const char* ptr = str.c_str(); str += " World"; // str可能重新分配内存 // 危险!ptr可能已经失效 cout << ptr; // 可能导致未定义行为 // 正确的做法 const char* new_ptr = str.c_str(); cout << new_ptr; // 安全
生命周期注意事项:
const char* getCharArray() { string str = "Hello"; return str.c_str(); // 错误!str已销毁 } // 正确的做法 string getString() { string str = "Hello"; return str; // 返回string对象 }
// 避免不必要的转换 void processString(const string& s) { // 直接使用string,无需转换 cout << s.length() << endl; cout << s.substr(0, 5) << endl; } // 必要时的转换 void legacyFunction(const char* s) { // 需要配合C风格API时使用转换 printf("%s\n", s); } string str = "Hello"; processString(str); // 直接使用string legacyFunction(str.c_str()); // 必要的转换 // 批量处理时的优化 string str = "Hello World"; const char* cstr = str.c_str(); // 多次使用cstr,但要确保str不会被修改 for(int i = 0; cstr[i]; i++) { // 处理cstr[i] }
string str = "Hello World"; // 使用正向迭代器 for(string::iterator it = str.begin(); it != str.end(); ++it) { *it = toupper(*it); // 转换为大写 } // 使用反向迭代器 for(string::reverse_iterator it = str.rbegin(); it != str.rend(); ++it) { cout << *it; // 反向输出 } // 使用范围for循环(C++11) for(char& c : str) { c = tolower(c); // 转换为小写 } // 常量迭代器 for(string::const_iterator it = str.cbegin(); it != str.cend(); ++it) { cout << *it; // 只读访问 }
常用算法:
#include <algorithm> string str = "Hello World"; // 排序 sort(str.begin(), str.end()); // 反转 reverse(str.begin(), str.end()); // 计数 int count = count_if(str.begin(), str.end(), ::isalpha); // 查找 auto it = find_if(str.begin(), str.end(), ::isupper);
自定义操作:
// 转换函数 bool isVowel(char c) { c = tolower(c); return c=='a' || c=='e' || c=='i' || c=='o' || c=='u'; } // 使用自定义函数 int vowels = count_if(str.begin(), str.end(), isVowel); // 使用lambda表达式(C++11) auto digits = count_if(str.begin(), str.end(), [](char c){ return isdigit(c); });
#include <sstream> // 字符串转数字 string str = "123 45.67"; stringstream ss(str); int n; double d; ss >> n >> d; // n=123, d=45.67 // 数字转字符串 stringstream ss2; ss2 << 456 << ' ' << 78.9; string result = ss2.str(); // "456 78.9" // 字符串分割 string text = "Hello,World,C++"; stringstream ss3(text); string token; while(getline(ss3, token, ',')) { cout << token << endl; } // 格式化字符串 stringstream ss4; ss4 << "Score: " << 95 << "%"; string formatted = ss4.str(); // "Score: 95%" // 清空并重用 ss4.str(""); ss4.clear(); ss4 << "New content";
// 单词计数 string text = "Hello World Hello C++"; stringstream ss(text); string word; map<string, int> wordCount; while(ss >> word) { wordCount[word]++; } // 输出每个单词的出现次数 for(const auto& pair : wordCount) { cout << pair.first << ": " << pair.second << endl; } // 文本格式化 string formatText(const string& text) { string result; bool lastWasSpace = true; // 用于处理开头的空格 for(char c : text) { if(isspace(c)) { if(!lastWasSpace) { result += ' '; lastWasSpace = true; } } else { result += c; lastWasSpace = false; } } // 移除末尾空格 if(!result.empty() && result.back() == ' ') { result.pop_back(); } return result; }
简单模式匹配:
// 查找所有匹配位置 vector<int> findAll(const string& text, const string& pattern) { vector<int> positions; size_t pos = 0; while((pos = text.find(pattern, pos)) != string::npos) { positions.push_back(pos); pos++; } return positions; }
通配符匹配:
// 支持?和*的简单通配符匹配 bool wildcardMatch(const string& text, const string& pattern) { int i = 0, j = 0; int starIdx = -1, iIdx = -1; while(i < text.length()) { if(j < pattern.length() && (pattern[j] == '?' || pattern[j] == text[i])) { i++; j++; } else if(j < pattern.length() && pattern[j] == '*') { starIdx = j; iIdx = i; j++; } else if(starIdx != -1) { j = starIdx + 1; i = ++iIdx; } else { return false; } } while(j < pattern.length() && pattern[j] == '*') { j++; } return j == pattern.length(); }
// 大小写转换 string convertCase(const string& str, bool toUpper) { string result = str; for(char& c : result) { if(toUpper) { c = toupper(c); } else { c = tolower(c); } } return result; } // 驼峰命名转换 string toCamelCase(const string& str) { string result; bool nextUpper = false; for(char c : str) { if(c == '_' || c == ' ') { nextUpper = true; } else { if(nextUpper) { result += toupper(c); nextUpper = false; } else { result += tolower(c); } } } return result; } // URL编码 string urlEncode(const string& str) { string result; for(char c : str) { if(isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { result += c; } else { result += '%'; char hex[3]; sprintf(hex, "%02X", (unsigned char)c); result += hex; } } return result; }
问题描述: 给定一行文本,将每个单词反转后输出,单词之间的空格保持不变。
示例:
"Hello World"
"olleH dlroW"
// HDU 1062 Text Reverse void solveTextReverse() { string line; while(getline(cin, line)) { stringstream ss(line); string word; bool first = true; while(ss >> word) { if(!first) cout << " "; reverse(word.begin(), word.end()); cout << word; first = false; } cout << endl; } }
问题描述: 给定m个长度为60的DNA序列,找出这些序列中最长的公共子串。如果有多个答案,输出字典序最小的那个。
// POJ 3080 Blue Jeans string findLongestCommonSubstring(vector<string>& dna) { if(dna.empty()) return ""; string result; const string& first = dna[0]; // 枚举所有可能的子串长度 for(int len = 60; len >= 3; len--) { // 枚举first中所有长度为len的子串 for(int i = 0; i + len <= first.length(); i++) { string sub = first.substr(i, len); bool found = true; // 检查是否在其他序列中都能找到 for(int j = 1; j < dna.size(); j++) { if(dna[j].find(sub) == string::npos) { found = false; break; } } if(found) { if(result.empty() || sub < result) { result = sub; } } } if(!result.empty()) break; } return result; }
问题描述: 给定一个加密规则和明文,将明文转换为密文。加密规则是将每个字母替换为另一个字母,保持大小写不变。
// CSP-J 2019 字符串加密 string encrypt(const string& text, const string& rule) { string result = text; // 创建映射表 map<char, char> upperMap, lowerMap; for(int i = 0; i < 26; i++) { char original = 'A' + i; char encrypted = toupper(rule[i]); upperMap[original] = encrypted; lowerMap[tolower(original)] = tolower(encrypted); } // 进行转换 for(char& c : result) { if(isupper(c)) { c = upperMap[c]; } else if(islower(c)) { c = lowerMap[c]; } } return result; } // 验证规则是否合法 bool isValidRule(const string& rule) { if(rule.length() != 26) return false; set<char> used; for(char c : rule) { if(!isalpha(c)) return false; char upper = toupper(c); if(used.count(upper)) return false; used.insert(upper); } return true; }
1. HDU 1062 - Text Reverse (★☆☆☆☆)
// 核心思路 string word; while(ss >> word) { reverse(word.begin(), word.end()); cout << word << " "; }
2. POJ 1159 - Palindrome (★★☆☆☆)
// 判断回文 bool isPalindrome(const string& s) { int i = 0, j = s.length() - 1; while(i < j) { if(s[i++] != s[j--]) return false; } return true; }
1. POJ 3080 - Blue Jeans (★★★☆☆)
// 核心思路 for(int len = maxLen; len >= 1; len--) { for(int i = 0; i + len <= s.length(); i++) { string sub = s.substr(i, len); if(isCommonSubstring(sub, strings)) { return sub; } } }
2. CSP-J 2019 - 字符串加密 (★★★☆☆)
// 核心思路 map<char, char> cipher; for(int i = 0; i < 26; i++) { cipher['A' + i] = rule[i]; cipher['a' + i] = tolower(rule[i]); }
USACO 2019 Dec Bronze
CSP-J 2022
POJ 3461
基础操作:
高级功能:
常见错误:
最佳实践:
深入学习:
实践应用:
扩展知识:
感谢学习! 如有疑问,请联系: judal@xmaker.org 魅客科创中心
这个讲义使用了Awesome Marp主题的蓝色风格。 内容针对已经学习过字符数组的学生,介绍C++ string类的使用。