Skip to content

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++编程的重要技能,为文本处理、用户界面、数据解析等应用提供基础。

本站内容仅供学习和研究使用。