Skip to content

字符串的处理

约 2715 字大约 9 分钟

2025-06-25

字符数组与相关函数

字符数组

在C++中,字符数组主要用于存储和处理字符串(由多个字符组成的序列),是信奥赛中处理文本数据的核心工具。C++提供了丰富的字符数组操作函数(需包含<cstring>头文件)。

一、字符数组的定义与初始化

字符数组的定义与初始化

字符数组本质是char类型的数组,以空字符'\0' 作为结束标志(区别于普通char数组)。

1. 定义方式

c++
char str1[10];  // 定义可存储10个字符的数组(含结束符)
char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'};  // 显式结束符
char str3[] = "Hello";  // 自动添加'\0',长度为6(5个字符+1个结束符)

关键特性

  • 字符串长度 = 有效字符数(不含'\0'),如"Hello"长度为5。
  • 数组容量需 ≥ 字符串长度 + 1(预留'\0'位置),否则会溢出。

2. 与普通字符数组的区别

  • 字符串数组:必须以'\0'结尾,可使用字符串函数处理(如strlenstrcpy)。
  • 普通字符数组:无需'\0',仅作为字符集合(如存储密码表)。

二、字符数组的输入与输出

字符数组的I/O有特殊语法,可直接读写整个字符串(无需循环)。

1. 输入方式

  • cin >> str:读入字符串,遇空格/回车/制表符停止,自动添加'\0'
c++
char str[100];
cin >> str;  // 输入"Hello World",实际只存入"Hello"(空格终止)
  • cin.getline(str, 容量):读入整行字符串(含空格),遇回车停止。
c++
char str[100];
cin.ignore();  // 清除缓冲区残留的换行符(若之前有输入)
cin.getline(str, 100);  // 输入"Hello World",完整存入
  • gets(str):读入整行(C语言函数,不安全,信奥赛建议用getline)。

2. 输出方式

  • cout << str:输出字符串,直到'\0'为止。
c++
char str[] = "Hello";
cout << str;  // 输出"Hello"(自动忽略'\0')
  • 循环输出每个字符:
c++
for (int i = 0; str[i] != '\0'; i++) {  // 以'\0'为终止条件
    cout << str[i];
}

三、常用字符串函数(<cstring>

字符串函数

信奥赛中频繁使用<cstring>库的函数处理字符数组,核心函数如下:

函数原型功能说明示例(str1="abc", str2="def"
strlen(str)计算字符串长度(不含'\0'strlen(str1) → 3
strcpy(dest, src)src复制到dest(需保证dest容量足够)strcpy(str1, str2)str1变为"def"
strcat(dest, src)src拼接在deststrcat(str1, str2) → "abcdef"
strcmp(str1, str2)比较字符串:相等返回0;str1>str2返回正strcmp("abc", "abd") → -1('c'<'d')
strchr(str, ch)查找chstr中第一次出现的位置strchr("abc", 'b') → 指向'b'的指针

函数使用示例:

c++

四、信奥赛核心应用

核心应用

1. 字符串逆序

c++
void reverseStr(char str[]) {
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        swap(str[i], str[len - 1 - i]);  // 首尾交换
    }
}

2. 统计字符出现次数

c++
int countChar(char str[], char ch) {
    int cnt = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        if (str[i] == ch) cnt++;
    }
    return cnt;
}

3. 字符串比较(模拟strcmp

c++
int myStrcmp(char str1[], char str2[]) {
    int i = 0;
    while (str1[i] != '\0' && str2[i] != '\0') {
        if (str1[i] != str2[i]) {
            return str1[i] - str2[i];  // 差值即比较结果
        }
        i++;
    }
    return str1[i] - str2[i];  // 处理长度不同的情况
}

五、避坑指南

避坑指南

  1. 数组容量不足

    • 复制/拼接字符串时,dest容量必须 ≥ src长度 + dest原长度 + 1(预留'\0'),否则会溢出。
      示例:
    c++
    char dest[5] = "Hi";
    char src[] = "Hello";
    strcat(dest, src);  // 错误:dest容量5 < 2+5+1=8,导致溢出
  2. 忘记添加'\0'
    手动赋值字符数组时,需在末尾加'\0',否则字符串函数会读取垃圾值。

    c++
    char str[6];
    for (int i = 0; i < 5; i++) {
        str[i] = 'A' + i;
    }
    str[5] = '\0';  // 必须添加,否则strlen结果未知
  3. cin >>getline 混用问题
    cin >> 后缓冲区会残留换行符,导致getline直接读空,需用cin.ignore()清除:

    c++
    int n;
    cin >> n;
    cin.ignore();  // 清除换行符
    char str[100];
    cin.getline(str, 100);  // 正确读入
  4. 字符串函数的返回值
    strcpystrcat返回dest的指针,strcmp返回比较结果,使用时需注意逻辑。

六、实战:判断回文字符串

判断回文字符串

回文字符串是指正读和反读都相同的字符串(如"abba"):

c++

重要

字符数组及相关函数是信奥赛中处理文本的基础,需熟练掌握初始化、I/O操作及字符串函数的使用。尤其要注意'\0'的作用和数组容量问题,避免溢出错误。对于复杂字符串操作,这些基础能力是解决问题的关键。

string类与相关函数

string类

在C++中,string类(定义于<string>头文件)是处理字符串的更便捷工具,相比字符数组,它无需需手动管理内存和结束符'\0',在信奥赛中广泛广泛应用。

一、string类的基本用法

string类的基本用法

1. 定义与初始化

string类的定义和初始化方式灵活,无需预先指定长度:

c++

2. 赋值与拼接

string类支持直接赋值和拼接,操作比字符数组更直观:

c++

二、string的访问与遍历

string的访问与遍历

1. 下标访问(类似数组)

string支持[]运算符访问单个字符,下标从0开始:

c++
string s = "Hello";
cout << s[0];  // 输出'H'
s[1] = 'i';    // 修改为"Hillo"

2. 迭代器访问(适合STL算法)

c++
for (string::iterator it = s.begin(); it != s.end(); it++) {
    cout << *it;  // 输出每个字符
}

3. 范围for循环(C++11及以上)

c++
for (char c : s) {  // 遍历每个字符
    cout << c;
}

三、常用成员函数(信奥赛高频)

string类提供了丰富的成员函数,以下是最常用的几种:

函数原型功能说明示例(s = "Hello"
length()/size()返回字符串长度(字符数)s.length() → 5
empty()判断字符串是否为空(空则返回trues.empty() → false
clear()清空字符串s.clear() → s变为空串
substr(pos, len)截取子串:从pos开始,长度len(默认到末尾)s.substr(1, 3) → "ell"
find(str, pos)pos开始查找str,返回首次出现位置;失败返回string::nposs.find("ll") → 2
replace(pos, len, str)pos开始,替换len个字符为strs.replace(1, 2, "i") → "Hio"
insert(pos, str)pos位置插入strs.insert(5, "!") → "Hello!"

四、常用非成员函数(<string>库)

函数原型功能说明示例
getline(cin, s)读入一整行字符串(含空格)到s输入"Hello World" → s为"Hello World"
to_string(num)将数字(int/double等)转换为stringto_string(123) → "123"
stoi(s)/stod(s)string转换为int/double(需包含<string>stoi("123") → 123
swap(s1, s2)交换两个string的值swap(s1, s2)

五、string与字符数组的转换

string与字符数组的转换

1. string → 字符数组

  • c_str():返回指向以'\0'结尾的字符数组的指针(用于需要C风格字符串的场景):
c++
string s = "Hello";
const char* arr = s.c_str();  // 转换为const char*

2. 字符数组 → string

  • 直接赋值即可:
c++
char arr[] = "World";
string s = arr;  // 自动转换

六、信奥赛核心应用

核心应用

1. 字符串反转

c++
#include <algorithm>  // 含reverse函数
string reverseStr(string s) {
    reverse(s.begin(), s.end());
    return s;
}

2. 统计子串出现次数

c++
int countSubstr(string s, string sub) {
    int cnt = 0;
    size_t pos = 0;  // 用size_t存储位置(避免负数)
    while ((pos = s.find(sub, pos)) != string::npos) {
        cnt++;
        pos += sub.length();  // 移动到下一个位置
    }
    return cnt;
}

3. 字符串排序

c++
#include <algorithm>
void sortString(string& s) {  // 按ASCII码排序字符
    sort(s.begin(), s.end());
}

七、避坑指南

避坑指南

  1. find函数的返回值
    未找到时返回string::npos(一个很大的数,通常定义为-1),判断时需用size_t类型接收:

    c++
    size_t pos = s.find("abc");
    if (pos != string::npos) {  // 正确判断:找到子串
        // ...
    }
  2. 下标越界
    s[i]访问越界时行为未定义(可能崩溃),可先用size()判断:

    c++
    if (i < s.size()) {  // 确保下标合法
        cout << s[i];
    }
  3. getlinecin混用
    cin >> x后缓冲区残留换行符,会导致getline读空,需用cin.ignore()清除:

    c++
    int n;
    cin >> n;
    cin.ignore();  // 清除换行符
    string s;
    getline(cin, s);  // 正确读入整行
  4. 字符串比较
    string支持直接用==!=<>等运算符比较(按字典序),无需用strcmp

    c++
    if (s1 == s2) { ... }  // 直接比较,比字符数组更方便

八、实战:字符串去重

字符串去重

题目:删除字符串中重复的字符,保留首次出现的字符(如"abacb"→"abc")。

c++

重要

string类是信奥赛中处理字符串的首选工具,其封装了内存管理和常用操作,大幅减少了字符数组的繁琐细节。熟练掌握string的成员函数和相关工具函数,能高效解决字符串处理问题,如文本分析、格式转换、子串匹配等。