跳转至

教程:深入理解 C 和 C++ 中的 charstring

第一部分:基础概念

1.1 char:字符的基本单位

  • 定义char 是 C 和 C++ 的基本数据类型,占用 1 字节(8 位),可以表示一个字符或一个整数(范围通常是 -128 到 127 或 0 到 255,取决于实现是否签名)。
  • 用途
  • 表示单个字符(如 'A''b')。
  • 通过数组或指针组成字符串(C 风格字符串)。
  • 初始化
    C
    1
    2
    3
    char c1 = 'A';         // 单字符,用单引号
    char c2 = 65;          // 等价于 'A'(ASCII 值)
    char str[] = "Hello";  // 字符数组,自动包含 '\0'
    

1.2 string:C++ 的字符串类

  • 定义string 是 C++ 标准库中的类(std::string),定义在 <string> 头文件中。它封装了对字符串的管理和操作。
  • 用途
  • 处理完整的字符串,支持动态长度和丰富操作。
  • 初始化
    C++
    1
    2
    3
    4
    #include <string>
    std::string s1 = "Hello";      // 直接初始化
    std::string s2(5, 'a');       // 初始化为 "aaaaa"
    std::string s3 = s1 + " World"; // 拼接初始化
    

1.3 核心联系

  • charstring 的构建块string 内部维护一个动态的 char 数组。
  • 转换
  • stringchar*:用 .c_str().data()
  • char*string:直接赋值或构造。

第二部分:操作与用法

2.1 char 的操作

  • 单个字符
  • 直接赋值、比较或打印。

    C
    1
    2
    3
    4
    5
    6
    #include <stdio.h>
    int main() {
        char c = 'A';
        printf("Character: %c, ASCII: %d\n", c, c); // 输出: Character: A, ASCII: 65
        return 0;
    }
    

  • C 风格字符串

  • char 数组或指针表示,末尾以 \0 结尾。
  • 操作依赖 <string.h> 的函数。
    C
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    #include <stdio.h>
    #include <string.h>
    int main() {
        char str1[] = "Hello";
        char str2[20];
        strcpy(str2, str1);      // 复制
        strcat(str2, " World");  // 拼接
        printf("Result: %s, Length: %lu\n", str2, strlen(str2));
        return 0;
    }
    // 输出: Result: Hello World, Length: 11
    

2.2 string 的操作

  • 基本操作
  • 拼接、访问、长度等。

    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <iostream>
    #include <string>
    int main() {
        std::string s = "Hello";
        s += " World";           // 拼接
        std::cout << s[0] << std::endl; // 访问首字符: H
        std::cout << "Length: " << s.length() << std::endl; // 输出: Length: 11
        return 0;
    }
    

  • 高级操作

  • 查找、替换、截取等。
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::string s = "Hello World";
    size_t pos = s.find("World");     // 查找子串
    if (pos != std::string::npos) {
        std::cout << "Found at: " << pos << std::endl; // 输出: 6
    }
    s.replace(pos, 5, "C++");         // 替换
    std::cout << s << std::endl;      // 输出: Hello C++
    std::string sub = s.substr(0, 5); // 截取
    std::cout << sub << std::endl;    // 输出: Hello
    

2.3 对比示例

  • 拼接
  • char
    C
    1
    2
    char str[20] = "Hello";
    strcat(str, " World");
    
  • string

    C++
    1
    2
    std::string s = "Hello";
    s += " World";
    

  • 长度

  • charstrlen(str)(不含 \0)。
  • strings.length()s.size()

第三部分:内存管理

3.1 char 的内存管理

  • 固定大小
  • char 数组的大小在定义时固定。
    C
    1
    2
    char str[5]; // 最多存 4 个字符 + '\0'
    strcpy(str, "Hello"); // 溢出!需要 6 字节
    
  • 手动管理
  • 动态分配用 mallocnew
    C
    1
    2
    3
    char* str = (char*)malloc(20);
    strcpy(str, "Hello");
    free(str); // 手动释放
    

3.2 string 的内存管理

  • 动态调整
  • string 自动分配和释放内存。
    C++
    1
    2
    std::string s = "Hello";
    s += " World"; // 自动扩展
    
  • 手动控制(可选):
  • reserve 预分配空间提高性能。
    C++
    1
    2
    3
    std::string s;
    s.reserve(100); // 预留 100 字节
    s = "Hello";
    

3.3 内存对比

  • char:需要开发者关注边界和释放。
  • string:自动管理,无需担心溢出或释放。

第四部分:实际应用场景

4.1 char 的典型用法

  • 与 C 库交互
    C
    1
    2
    3
    #include <stdio.h>
    char str[] = "Hello";
    printf("%s\n", str);
    
  • 低级操作
    C
    1
    2
    3
    4
    5
    char buffer[256];
    int i = 0;
    while ((buffer[i] = getchar()) != '\n' && i < 255) i++;
    buffer[i] = '\0';
    printf("Input: %s\n", buffer);
    

4.2 string 的典型用法

  • 用户输入处理
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <iostream>
    #include <string>
    int main() {
        std::string input;
        std::cout << "Enter text: ";
        std::getline(std::cin, input); // 支持多词输入
        std::cout << "You entered: " << input << std::endl;
        return 0;
    }
    
  • 文件路径操作
    C++
    1
    2
    std::string path = "/usr/local";
    path += "/bin";
    

4.3 混合使用

  • 日志格式化
    C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "spdlog/spdlog.h"
    int main() {
        auto logger = spdlog::stdout_color_mt("console");
        char c = 'A';
        std::string s = "Error code: ";
        s += c;
        logger->error(s);
        return 0;
    }
    

第五部分:高级主题

5.1 char 的变体

  • signed charunsigned char
  • signed char:-128 到 127。
  • unsigned char:0 到 255。

    C
    1
    2
    unsigned char uc = 255;
    printf("%d\n", uc); // 输出: 255
    

  • const char*

  • 表示只读字符串,常用于函数参数。
    C
    1
    2
    3
    void print(const char* s) {
        printf("%s\n", s);
    }
    

5.2 string 的高级功能

  • 迭代器
    C++
    1
    2
    3
    4
    std::string s = "Hello";
    for (auto it = s.begin(); it != s.end(); ++it) {
        std::cout << *it << " ";
    } // 输出: H e l l o
    
  • 容量管理
    C++
    1
    2
    3
    4
    std::string s = "Hello";
    std::cout << "Size: " << s.size() << ", Capacity: " << s.capacity() << std::endl;
    s.reserve(50);
    std::cout << "New Capacity: " << s.capacity() << std::endl;
    

第六部分:注意事项与最佳实践

6.1 char

  • 缓冲区溢出
  • 始终确保数组足够大。
    C
    1
    2
    char str[5];
    strcpy(str, "Hello"); // 危险!溢出
    
  • 空字符
  • 手动添加 \0
    C
    1
    char str[6] = {'H', 'e', 'l', 'l', 'o'}; // 无 '\0',不是合法字符串
    

6.2 string

  • 性能
  • 小字符串操作频繁时,避免过多拷贝。
    C++
    1
    2
    3
    4
    5
    std::string s;
    for (int i = 0; i < 1000; i++) s += "a"; // 低效
    // 优化:
    s.reserve(1000);
    for (int i = 0; i < 1000; i++) s += "a";
    
  • 异常安全
  • 检查操作是否成功。
    C++
    1
    2
    std::string s;
    if (s.empty()) std::cout << "Empty string" << std::endl;
    

6.3 string 到 char*(C 风格字符串)

方法: - 用 .c_str():返回只读的 const char*。 - 用 .data():返回底层字符数组的指针(C++11 前是 const char*,之后可修改但需谨慎)。 - 用 copy:将内容复制到现有的 char 数组。 示例:

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>
#include <cstring>
int main() {
    std::string s = "Hello World";

    // 方法 1:c_str()
    const char* cstr = s.c_str();
    std::cout << "cstr: " << cstr << std::endl; // 输出: Hello World

    // 方法 2:data() (只读用法)
    const char* data = s.data();
    std::cout << "data: " << data << std::endl; // 输出: Hello World

    // 方法 3:copy 到 char 数组
    char buffer[20];
    s.copy(buffer, 5, 0); // 从位置 0 复制 5 个字符
    buffer[5] = '\0';     // 手动添加结尾
    std::cout << "buffer: " << buffer << std::endl; // 输出: Hello

    return 0;
}


第七部分:总结

  • char
  • 适合低级控制、C 兼容场景。
  • 需要手动管理内存和边界。
  • string
  • 适合现代 C++ 开发,功能强大且安全。
  • 自动管理内存,操作简便。
  • 选择依据
  • char:需要与 C 库交互或极致性能。
  • string:需要便捷性和复杂操作。

int main(int argc, char **argv)

int main(int argc, char **argv) 是程序主函数的一种标准签名,用于接收命令行参数 - argc:表示命令行参数的数量(argument count),包括程序名本身。 - argv:表示命令行参数的内容(argument vector),是一个字符串数组。

char** 的含义

char** 是指向指针的指针: - char*:指向一个字符数组(字符串)。 - char**:指向一个指针数组,而这些指针又指向字符串。

为什么不用其他类型?
  • 为什么不用 char*char* 只能表示单个字符串,无法表示多个字符串的集合。 示例:char* argv 只能存储 "hello",无法容纳 "hello" 和 "world"。

  • 为什么不用 std::string? main 是 C 的遗产,设计时没有 C++ 的 std::string。 保持与 C 兼容性,避免依赖 C++ 标准库。