C++ 字符串
概述
字符串是程序中处理文本数据的重要工具。C++提供了两种主要的字符串处理方式:C风格字符串(字符数组)和C++标准库的std::string类。现代C++编程中推荐使用std::string,因为它更安全、功能更丰富。
🔤 C风格字符串
基本概念和操作
cpp
#include <iostream>
#include <cstring>
int main() {
std::cout << "=== C风格字符串 ===" << std::endl;
// 1. 字符串字面量和字符数组
const char* str1 = "Hello World"; // 字符串字面量
char str2[] = "C++ Programming"; // 字符数组
char str3[20] = "Dynamic"; // 指定大小的字符数组
std::cout << "str1: " << str1 << std::endl;
std::cout << "str2: " << str2 << std::endl;
std::cout << "str3: " << str3 << std::endl;
// 2. 字符串长度
std::cout << "\n=== 字符串长度 ===" << std::endl;
std::cout << "strlen(str1): " << strlen(str1) << std::endl;
std::cout << "strlen(str2): " << strlen(str2) << std::endl;
// 3. 字符串复制
char destination[50];
strcpy(destination, str1);
std::cout << "复制结果: " << destination << std::endl;
// 安全复制(指定最大长度)
strncpy(destination, str2, sizeof(destination) - 1);
destination[sizeof(destination) - 1] = '\0'; // 确保null终止
std::cout << "安全复制: " << destination << std::endl;
// 4. 字符串连接
char combined[100] = "Hello ";
strcat(combined, "World!");
std::cout << "连接结果: " << combined << std::endl;
// 5. 字符串比较
char str4[] = "Hello";
char str5[] = "World";
int cmp1 = strcmp(str4, "Hello");
int cmp2 = strcmp(str4, str5);
std::cout << "\n=== 字符串比较 ===" << std::endl;
std::cout << "strcmp(str4, \"Hello\"): " << cmp1 << " (相等)" << std::endl;
std::cout << "strcmp(str4, str5): " << cmp2 << " (str4 < str5)" << std::endl;
return 0;
}C风格字符串的局限性
cpp
#include <iostream>
#include <cstring>
int main() {
std::cout << "=== C风格字符串的问题 ===" << std::endl;
// 1. 缓冲区溢出风险
char buffer[10];
const char* long_string = "This is a very long string";
// 危险的操作(会导致缓冲区溢出)
// strcpy(buffer, long_string); // 不要这样做!
// 安全的做法
strncpy(buffer, long_string, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
std::cout << "截断后的字符串: " << buffer << std::endl;
// 2. 内存管理复杂
char* dynamic_str = new char[20];
strcpy(dynamic_str, "Dynamic string");
std::cout << "动态字符串: " << dynamic_str << std::endl;
delete[] dynamic_str; // 必须手动释放内存
// 3. 功能有限
std::cout << "\n=== 功能限制 ===" << std::endl;
std::cout << "C风格字符串不支持:" << std::endl;
std::cout << "- 自动内存管理" << std::endl;
std::cout << "- 运算符重载" << std::endl;
std::cout << "- 安全的边界检查" << std::endl;
std::cout << "- 丰富的字符串操作函数" << std::endl;
return 0;
}📝 std::string类
基本操作
cpp
#include <iostream>
#include <string>
int main() {
std::cout << "=== std::string基本操作 ===" << std::endl;
// 1. 字符串创建和初始化
std::string str1; // 空字符串
std::string str2 = "Hello World"; // 字符串字面量初始化
std::string str3("C++ Programming"); // 构造函数初始化
std::string str4(str2); // 拷贝构造
std::string str5(10, 'A'); // 重复字符
std::cout << "str1: \"" << str1 << "\"" << std::endl;
std::cout << "str2: " << str2 << std::endl;
std::cout << "str3: " << str3 << std::endl;
std::cout << "str4: " << str4 << std::endl;
std::cout << "str5: " << str5 << std::endl;
// 2. 字符串属性
std::cout << "\n=== 字符串属性 ===" << std::endl;
std::cout << "str2长度: " << str2.length() << std::endl;
std::cout << "str2大小: " << str2.size() << std::endl;
std::cout << "str2容量: " << str2.capacity() << std::endl;
std::cout << "str1是否为空: " << (str1.empty() ? "是" : "否") << std::endl;
// 3. 字符访问
std::cout << "\n=== 字符访问 ===" << std::endl;
std::cout << "str2[0]: " << str2[0] << std::endl;
std::cout << "str2.at(6): " << str2.at(6) << std::endl; // 安全访问
std::cout << "str2.front(): " << str2.front() << std::endl;
std::cout << "str2.back(): " << str2.back() << std::endl;
// 4. 字符串修改
str2[0] = 'h'; // 修改单个字符
std::cout << "修改后的str2: " << str2 << std::endl;
return 0;
}字符串操作和连接
cpp
#include <iostream>
#include <string>
int main() {
std::cout << "=== 字符串操作 ===" << std::endl;
std::string str1 = "Hello";
std::string str2 = "World";
// 1. 字符串连接
std::string result = str1 + " " + str2;
std::cout << "连接结果: " << result << std::endl;
// 使用append方法
std::string greeting = "Hello";
greeting.append(" ");
greeting.append(str2);
greeting.append("!");
std::cout << "append结果: " << greeting << std::endl;
// 使用+=运算符
std::string message = "C++";
message += " is";
message += " awesome!";
std::cout << "+=结果: " << message << std::endl;
// 2. 字符串插入
std::string text = "Hello World";
text.insert(5, " Beautiful");
std::cout << "插入后: " << text << std::endl;
// 3. 字符串替换
std::string original = "I love Java programming";
original.replace(7, 4, "C++"); // 替换"Java"为"C++"
std::cout << "替换后: " << original << std::endl;
// 4. 字符串删除
std::string sample = "Hello Beautiful World";
sample.erase(5, 10); // 删除" Beautiful"
std::cout << "删除后: " << sample << std::endl;
// 5. 字符串清空和重置
std::string temp = "Temporary";
std::cout << "清空前: " << temp << " (长度: " << temp.length() << ")" << std::endl;
temp.clear();
std::cout << "清空后: \"" << temp << "\" (长度: " << temp.length() << ")" << std::endl;
return 0;
}字符串查找和比较
cpp
#include <iostream>
#include <string>
int main() {
std::cout << "=== 字符串查找 ===" << std::endl;
std::string text = "The quick brown fox jumps over the lazy dog";
// 1. 查找子字符串
size_t pos = text.find("quick");
if (pos != std::string::npos) {
std::cout << "找到'quick'在位置: " << pos << std::endl;
}
// 查找字符
pos = text.find('o');
std::cout << "第一个'o'在位置: " << pos << std::endl;
// 从指定位置开始查找
pos = text.find('o', pos + 1);
std::cout << "第二个'o'在位置: " << pos << std::endl;
// 反向查找
pos = text.rfind('o');
std::cout << "最后一个'o'在位置: " << pos << std::endl;
// 2. 查找多个字符中的任意一个
pos = text.find_first_of("aeiou");
std::cout << "第一个元音字母在位置: " << pos << " ('" << text[pos] << "')" << std::endl;
pos = text.find_last_of("aeiou");
std::cout << "最后一个元音字母在位置: " << pos << " ('" << text[pos] << "')" << std::endl;
// 3. 字符串比较
std::cout << "\n=== 字符串比较 ===" << std::endl;
std::string str1 = "apple";
std::string str2 = "banana";
std::string str3 = "apple";
std::cout << "str1 == str3: " << (str1 == str3) << std::endl;
std::cout << "str1 != str2: " << (str1 != str2) << std::endl;
std::cout << "str1 < str2: " << (str1 < str2) << std::endl;
// 使用compare方法
int cmp = str1.compare(str2);
std::cout << "str1.compare(str2): " << cmp << std::endl;
return 0;
}子字符串和转换
cpp
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::cout << "=== 子字符串操作 ===" << std::endl;
std::string sentence = "Hello C++ Programming World";
// 1. 提取子字符串
std::string sub1 = sentence.substr(6, 3); // "C++"
std::string sub2 = sentence.substr(10); // 从位置10到末尾
std::cout << "原字符串: " << sentence << std::endl;
std::cout << "substr(6, 3): " << sub1 << std::endl;
std::cout << "substr(10): " << sub2 << std::endl;
// 2. 大小写转换
std::cout << "\n=== 大小写转换 ===" << std::endl;
std::string text = "Hello World";
std::string upper_text = text;
std::string lower_text = text;
// 转换为大写
std::transform(upper_text.begin(), upper_text.end(), upper_text.begin(), ::toupper);
std::cout << "大写: " << upper_text << std::endl;
// 转换为小写
std::transform(lower_text.begin(), lower_text.end(), lower_text.begin(), ::tolower);
std::cout << "小写: " << lower_text << std::endl;
// 3. 字符串和数字转换
std::cout << "\n=== 数字转换 ===" << std::endl;
// 数字转字符串
int number = 42;
double decimal = 3.14159;
std::string str_num = std::to_string(number);
std::string str_dec = std::to_string(decimal);
std::cout << "数字转字符串: " << number << " -> \"" << str_num << "\"" << std::endl;
std::cout << "小数转字符串: " << decimal << " -> \"" << str_dec << "\"" << std::endl;
// 字符串转数字
std::string num_str = "123";
std::string dec_str = "45.67";
try {
int converted_int = std::stoi(num_str);
double converted_double = std::stod(dec_str);
std::cout << "字符串转数字: \"" << num_str << "\" -> " << converted_int << std::endl;
std::cout << "字符串转小数: \"" << dec_str << "\" -> " << converted_double << std::endl;
}
catch (const std::exception& e) {
std::cout << "转换错误: " << e.what() << std::endl;
}
return 0;
}🔍 字符串处理技巧
字符串分割和合并
cpp
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
// 字符串分割函数
std::vector<std::string> split(const std::string& str, char delimiter) {
std::vector<std::string> tokens;
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
// 字符串合并函数
std::string join(const std::vector<std::string>& strings, const std::string& delimiter) {
if (strings.empty()) return "";
std::string result = strings[0];
for (size_t i = 1; i < strings.size(); i++) {
result += delimiter + strings[i];
}
return result;
}
int main() {
std::cout << "=== 字符串分割和合并 ===" << std::endl;
// 1. 字符串分割
std::string csv_data = "apple,banana,orange,grape";
std::vector<std::string> fruits = split(csv_data, ',');
std::cout << "原字符串: " << csv_data << std::endl;
std::cout << "分割结果: ";
for (const auto& fruit : fruits) {
std::cout << "\"" << fruit << "\" ";
}
std::cout << std::endl;
// 2. 字符串合并
std::vector<std::string> words = {"Hello", "C++", "Programming", "World"};
std::string joined = join(words, " ");
std::cout << "\n合并结果: " << joined << std::endl;
// 3. 使用stringstream处理复杂格式
std::cout << "\n=== stringstream应用 ===" << std::endl;
std::string data = "John 25 Engineer 75000";
std::stringstream ss(data);
std::string name, job;
int age, salary;
ss >> name >> age >> job >> salary;
std::cout << "解析结果:" << std::endl;
std::cout << "姓名: " << name << std::endl;
std::cout << "年龄: " << age << std::endl;
std::cout << "职业: " << job << std::endl;
std::cout << "薪水: " << salary << std::endl;
return 0;
}字符串去除空白和验证
cpp
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
// 去除字符串开头的空白
std::string ltrim(const std::string& str) {
auto start = std::find_if(str.begin(), str.end(), [](unsigned char ch) {
return !std::isspace(ch);
});
return std::string(start, str.end());
}
// 去除字符串末尾的空白
std::string rtrim(const std::string& str) {
auto end = std::find_if(str.rbegin(), str.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base();
return std::string(str.begin(), end);
}
// 去除字符串两端的空白
std::string trim(const std::string& str) {
return ltrim(rtrim(str));
}
// 检查字符串是否为数字
bool isNumber(const std::string& str) {
if (str.empty()) return false;
size_t start = 0;
if (str[0] == '+' || str[0] == '-') {
start = 1;
if (str.length() == 1) return false;
}
bool hasDecimal = false;
for (size_t i = start; i < str.length(); i++) {
if (str[i] == '.') {
if (hasDecimal) return false;
hasDecimal = true;
} else if (!std::isdigit(str[i])) {
return false;
}
}
return true;
}
// 检查是否为有效邮箱(简化版)
bool isValidEmail(const std::string& email) {
size_t at_pos = email.find('@');
if (at_pos == std::string::npos || at_pos == 0 || at_pos == email.length() - 1) {
return false;
}
size_t dot_pos = email.find('.', at_pos);
return dot_pos != std::string::npos && dot_pos > at_pos + 1 && dot_pos < email.length() - 1;
}
int main() {
std::cout << "=== 字符串处理工具 ===" << std::endl;
// 1. 去除空白测试
std::string messy = " Hello World ";
std::cout << "原字符串: \"" << messy << "\"" << std::endl;
std::cout << "ltrim: \"" << ltrim(messy) << "\"" << std::endl;
std::cout << "rtrim: \"" << rtrim(messy) << "\"" << std::endl;
std::cout << "trim: \"" << trim(messy) << "\"" << std::endl;
// 2. 数字验证测试
std::cout << "\n=== 数字验证 ===" << std::endl;
std::vector<std::string> test_numbers = {"123", "45.67", "-89", "+12.34", "abc", "12.34.56", ""};
for (const auto& num : test_numbers) {
std::cout << "\"" << num << "\" 是数字: " << (isNumber(num) ? "是" : "否") << std::endl;
}
// 3. 邮箱验证测试
std::cout << "\n=== 邮箱验证 ===" << std::endl;
std::vector<std::string> test_emails = {
"user@example.com",
"test@test",
"@example.com",
"user@",
"valid.email@domain.org",
"invalid.email"
};
for (const auto& email : test_emails) {
std::cout << "\"" << email << "\" 是有效邮箱: " << (isValidEmail(email) ? "是" : "否") << std::endl;
}
return 0;
}🚀 高级字符串特性
字符串流处理
cpp
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
int main() {
std::cout << "=== 字符串流处理 ===" << std::endl;
// 1. 格式化输出到字符串
std::ostringstream oss;
oss << "数字: " << 42 << ", 小数: " << std::fixed << std::setprecision(2) << 3.14159;
std::string formatted = oss.str();
std::cout << "格式化结果: " << formatted << std::endl;
// 2. 从字符串读取数据
std::string data = "123 45.67 hello world";
std::istringstream iss(data);
int num;
double dec;
std::string word1, word2;
iss >> num >> dec >> word1 >> word2;
std::cout << "\n解析结果:" << std::endl;
std::cout << "整数: " << num << std::endl;
std::cout << "小数: " << dec << std::endl;
std::cout << "单词1: " << word1 << std::endl;
std::cout << "单词2: " << word2 << std::endl;
// 3. 字符串替换所有匹配项
auto replaceAll = [](std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
return str;
};
std::string text = "Hello world, world is beautiful, world is amazing";
std::string replaced = replaceAll(text, "world", "C++");
std::cout << "\n替换前: " << text << std::endl;
std::cout << "替换后: " << replaced << std::endl;
return 0;
}性能考虑和最佳实践
cpp
#include <iostream>
#include <string>
#include <chrono>
// 性能测试函数
void performanceTest() {
const int iterations = 100000;
// 方法1:使用+操作符连接
auto start = std::chrono::high_resolution_clock::now();
std::string result1;
for (int i = 0; i < iterations; i++) {
result1 = result1 + "a";
}
auto end = std::chrono::high_resolution_clock::now();
auto time1 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// 方法2:使用append方法
start = std::chrono::high_resolution_clock::now();
std::string result2;
for (int i = 0; i < iterations; i++) {
result2.append("a");
}
end = std::chrono::high_resolution_clock::now();
auto time2 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// 方法3:预分配空间
start = std::chrono::high_resolution_clock::now();
std::string result3;
result3.reserve(iterations); // 预分配空间
for (int i = 0; i < iterations; i++) {
result3.append("a");
}
end = std::chrono::high_resolution_clock::now();
auto time3 = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "性能测试结果 (" << iterations << " 次操作):" << std::endl;
std::cout << "+=操作符: " << time1.count() << "ms" << std::endl;
std::cout << "append方法: " << time2.count() << "ms" << std::endl;
std::cout << "预分配+append: " << time3.count() << "ms" << std::endl;
}
int main() {
std::cout << "=== 字符串最佳实践 ===" << std::endl;
// 1. 选择合适的初始化方式
std::string str1 = "Hello"; // 推荐:简洁
std::string str2("Hello"); // 也可以
std::string str3 = std::string("Hello"); // 不推荐:冗余
// 2. 使用const引用传递字符串参数
auto printString = [](const std::string& str) {
std::cout << "字符串: " << str << std::endl;
};
printString("Hello World");
// 3. 合理使用reserve避免重复分配
std::string longString;
longString.reserve(1000); // 如果知道大概大小,预分配
// 4. 使用字符串字面量连接
std::string message = "Hello " "World " "from " "C++"; // 编译时连接
std::cout << "连接的消息: " << message << std::endl;
// 5. 性能测试
performanceTest();
// 6. 避免不必要的拷贝
std::string data = "Important data";
// 不好:创建拷贝
std::string copy = data.substr(0, 9);
// 更好:使用string_view (C++17)
// std::string_view view = data; // 只是视图,不拷贝
std::cout << "\n字符串使用建议:" << std::endl;
std::cout << "1. 优先使用std::string而非C风格字符串" << std::endl;
std::cout << "2. 函数参数使用const引用" << std::endl;
std::cout << "3. 预分配空间避免重复内存分配" << std::endl;
std::cout << "4. 注意字符串拷贝的性能开销" << std::endl;
return 0;
}总结
C++字符串处理提供了从基础到高级的完整解决方案:
字符串类型选择
| 类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| C风格字符串 | C代码兼容 | 内存效率高 | 不安全,功能有限 |
| std::string | 现代C++开发 | 安全,功能丰富 | 稍有性能开销 |
核心特性
- 基本操作:创建、访问、修改、连接
- 查找比较:find系列方法,比较运算符
- 转换处理:大小写转换,数字转换
- 高级功能:分割合并,格式化,流处理
最佳实践
- 优先使用std::string而非C风格字符串
- 函数参数使用const std::string&传递
- 合理使用reserve()预分配空间
- 注意字符串操作的性能影响
- 进行适当的输入验证和错误处理
掌握字符串处理是C++编程的重要技能,为文本处理、用户界面、数据解析等应用提供基础。