字符串的处理
约 2715 字大约 9 分钟
2025-06-25
字符数组与相关函数
字符数组
在C++中,字符数组主要用于存储和处理字符串(由多个字符组成的序列),是信奥赛中处理文本数据的核心工具。C++提供了丰富的字符数组操作函数(需包含<cstring>
头文件)。
一、字符数组的定义与初始化
字符数组的定义与初始化
字符数组本质是char
类型的数组,以空字符'\0'
作为结束标志(区别于普通char
数组)。
1. 定义方式
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'
结尾,可使用字符串函数处理(如strlen
、strcpy
)。 - 普通字符数组:无需
'\0'
,仅作为字符集合(如存储密码表)。
二、字符数组的输入与输出
字符数组的I/O有特殊语法,可直接读写整个字符串(无需循环)。
1. 输入方式
cin >> str
:读入字符串,遇空格/回车/制表符停止,自动添加'\0'
。
char str[100];
cin >> str; // 输入"Hello World",实际只存入"Hello"(空格终止)
cin.getline(str, 容量)
:读入整行字符串(含空格),遇回车停止。
char str[100];
cin.ignore(); // 清除缓冲区残留的换行符(若之前有输入)
cin.getline(str, 100); // 输入"Hello World",完整存入
gets(str)
:读入整行(C语言函数,不安全,信奥赛建议用getline
)。
2. 输出方式
cout << str
:输出字符串,直到'\0'
为止。
char str[] = "Hello";
cout << str; // 输出"Hello"(自动忽略'\0')
- 循环输出每个字符:
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 拼接在dest 后 | strcat(str1, str2) → "abcdef" |
strcmp(str1, str2) | 比较字符串:相等返回0;str1>str2 返回正 | strcmp("abc", "abd") → -1('c'<'d') |
strchr(str, ch) | 查找ch 在str 中第一次出现的位置 | strchr("abc", 'b') → 指向'b'的指针 |
函数使用示例:
#include <iostream>
#include <cstring> // 包含字符串函数
using namespace std;
int main() {
char str1[20] = "Hello";
char str2[10] = "World";
// 求长度
cout << strlen(str1) << endl; // 输出5
// 复制
strcpy(str1, "Hi"); // str1变为"Hi"
cout << str1 << endl;
// 拼接
strcat(str1, str2); // str1变为"HiWorld"
cout << str1 << endl;
// 比较
if (strcmp(str1, str2) > 0) {
cout << "str1 > str2" << endl;
}
return 0;
}
四、信奥赛核心应用
核心应用
1. 字符串逆序
void reverseStr(char str[]) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
swap(str[i], str[len - 1 - i]); // 首尾交换
}
}
2. 统计字符出现次数
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
)
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]; // 处理长度不同的情况
}
五、避坑指南
避坑指南
数组容量不足:
- 复制/拼接字符串时,
dest
容量必须 ≥src
长度 +dest
原长度 + 1(预留'\0'
),否则会溢出。
示例:
c++char dest[5] = "Hi"; char src[] = "Hello"; strcat(dest, src); // 错误:dest容量5 < 2+5+1=8,导致溢出
- 复制/拼接字符串时,
忘记添加
'\0'
:
手动赋值字符数组时,需在末尾加'\0'
,否则字符串函数会读取垃圾值。c++char str[6]; for (int i = 0; i < 5; i++) { str[i] = 'A' + i; } str[5] = '\0'; // 必须添加,否则strlen结果未知
cin >>
与getline
混用问题:cin >>
后缓冲区会残留换行符,导致getline
直接读空,需用cin.ignore()
清除:c++int n; cin >> n; cin.ignore(); // 清除换行符 char str[100]; cin.getline(str, 100); // 正确读入
字符串函数的返回值:
strcpy
、strcat
返回dest
的指针,strcmp
返回比较结果,使用时需注意逻辑。
六、实战:判断回文字符串
判断回文字符串
回文字符串是指正读和反读都相同的字符串(如"abba"):
#include <iostream>
#include <cstring>
using namespace std;
bool isPalindrome(char str[]) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
if (str[i] != str[len - 1 - i]) {
return false;
}
}
return true;
}
int main() {
char str[100];
cout << "输入字符串:";
cin.getline(str, 100);
if (isPalindrome(str)) {
cout << "是回文串" << endl;
} else {
cout << "不是回文串" << endl;
}
return 0;
}
重要
字符数组及相关函数是信奥赛中处理文本的基础,需熟练掌握初始化、I/O操作及字符串函数的使用。尤其要注意'\0'
的作用和数组容量问题,避免溢出错误。对于复杂字符串操作,这些基础能力是解决问题的关键。
string类与相关函数
string类
在C++中,string
类(定义于<string>
头文件)是处理字符串的更便捷工具,相比字符数组,它无需需手动管理内存和结束符'\0'
,在信奥赛中广泛广泛应用。
一、string类的基本用法
string类的基本用法
1. 定义与初始化
string
类的定义和初始化方式灵活,无需预先指定长度:
#include <string> // 必须包含此头文件
using namespace std;
string s1; // 空字符串
string s2 = "Hello"; // 直接初始化
string s3("World"); // 构造函数初始化
string s4(5, 'a'); // 重复字符:"aaaaa"
string s5 = s2 + " " + s3; // 拼接初始化:"Hello World"
2. 赋值与拼接
string
类支持直接赋值和拼接,操作比字符数组更直观:
string s = "Hello";
// 赋值
s = "Hi"; // 直接赋值,无需考虑容量
// 拼接
s += " there"; // 追加字符串 → "Hi there"
s = s + "!"; // 拼接后赋值 → "Hi there!"
二、string的访问与遍历
string的访问与遍历
1. 下标访问(类似数组)
string
支持[]
运算符访问单个字符,下标从0开始:
string s = "Hello";
cout << s[0]; // 输出'H'
s[1] = 'i'; // 修改为"Hillo"
2. 迭代器访问(适合STL算法)
for (string::iterator it = s.begin(); it != s.end(); it++) {
cout << *it; // 输出每个字符
}
3. 范围for循环(C++11及以上)
for (char c : s) { // 遍历每个字符
cout << c;
}
三、常用成员函数(信奥赛高频)
string
类提供了丰富的成员函数,以下是最常用的几种:
函数原型 | 功能说明 | 示例(s = "Hello" ) |
---|---|---|
length() /size() | 返回字符串长度(字符数) | s.length() → 5 |
empty() | 判断字符串是否为空(空则返回true ) | s.empty() → false |
clear() | 清空字符串 | s.clear() → s变为空串 |
substr(pos, len) | 截取子串:从pos 开始,长度len (默认到末尾) | s.substr(1, 3) → "ell" |
find(str, pos) | 从pos 开始查找str ,返回首次出现位置;失败返回string::npos | s.find("ll") → 2 |
replace(pos, len, str) | 从pos 开始,替换len 个字符为str | s.replace(1, 2, "i") → "Hio" |
insert(pos, str) | 在pos 位置插入str | s.insert(5, "!") → "Hello!" |
四、常用非成员函数(<string>
库)
函数原型 | 功能说明 | 示例 |
---|---|---|
getline(cin, s) | 读入一整行字符串(含空格)到s | 输入"Hello World" → s为"Hello World" |
to_string(num) | 将数字(int/double等)转换为string | to_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风格字符串的场景):
string s = "Hello";
const char* arr = s.c_str(); // 转换为const char*
2. 字符数组 → string
- 直接赋值即可:
char arr[] = "World";
string s = arr; // 自动转换
六、信奥赛核心应用
核心应用
1. 字符串反转
#include <algorithm> // 含reverse函数
string reverseStr(string s) {
reverse(s.begin(), s.end());
return s;
}
2. 统计子串出现次数
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. 字符串排序
#include <algorithm>
void sortString(string& s) { // 按ASCII码排序字符
sort(s.begin(), s.end());
}
七、避坑指南
避坑指南
find
函数的返回值:
未找到时返回string::npos
(一个很大的数,通常定义为-1
),判断时需用size_t
类型接收:c++size_t pos = s.find("abc"); if (pos != string::npos) { // 正确判断:找到子串 // ... }
下标越界:
s[i]
访问越界时行为未定义(可能崩溃),可先用size()
判断:c++if (i < s.size()) { // 确保下标合法 cout << s[i]; }
getline
与cin
混用:cin >> x
后缓冲区残留换行符,会导致getline
读空,需用cin.ignore()
清除:c++int n; cin >> n; cin.ignore(); // 清除换行符 string s; getline(cin, s); // 正确读入整行
字符串比较:
string
支持直接用==
、!=
、<
、>
等运算符比较(按字典序),无需用strcmp
:c++if (s1 == s2) { ... } // 直接比较,比字符数组更方便
八、实战:字符串去重
字符串去重
题目:删除字符串中重复的字符,保留首次出现的字符(如"abacb"→"abc")。
#include <iostream>
#include <string>
using namespace std;
string removeDuplicates(string s) {
string res;
for (char c : s) {
// 若当前字符不在res中,则添加
if (res.find(c) == string::npos) {
res += c;
}
}
return res;
}
int main() {
string s;
cout << "输入字符串:";
getline(cin, s);
cout << "去重后:" << removeDuplicates(s) << endl;
return 0;
}
重要
string
类是信奥赛中处理字符串的首选工具,其封装了内存管理和常用操作,大幅减少了字符数组的繁琐细节。熟练掌握string
的成员函数和相关工具函数,能高效解决字符串处理问题,如文本分析、格式转换、子串匹配等。