第25章 字符串与字符数组
| 等级 | 知识块 | 考查频率 |
|---|---|---|
| GESP C++ 三级 | 字符串及其函数(大小写转换、查找、分割、替换) | ⭐⭐⭐ |
字符串是表示文本信息的基础。C 语言用字符数组实现字符串;C++ 额外提供 string 类简化操作。三级要求掌握字符数组、cstring 函数与 string 类的常用操作。
25.1 字符数组与字符串基础概念
25.1.1 字符数组
存储字符类型的数组,不一定带结束符 \0,此时它只是字符集合,不是字符串。
char arr[3] = {'A', 'B', 'C'}; // 纯字符数组,无 '\0',不是字符串
25.1.2 字符串
以空字符 \0(ASCII 0)作为结束标记的字符序列,必须存放在字符数组中。
char str1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str2[] = "World"; // 编译器自动末尾追加 '\0'
25.2 字符数组定义与初始化
25.2.1 逐个字符初始化
char c1[6] = {'C', 'h', 'i', 'n', 'a', '\0'}; // 合法字符串
char c2[3] = {'a', 'b', 'c'}; // 仅字符数组,无结束符
25.2.2 字符串常量初始化
直接用双引号,编译器自动补 \0:
char s1[] = "Hello"; // 长度 6:H e l l o \0
char s2[10] = "Hi"; // 前两位 H i,其余填 '\0'
\0 的位置char s[5] = "Hello"; 会出错:"Hello" 实际占 6 字节(含 \0),但数组只有 5。定义字符数组时长度应 ≥ 字符数 + 1。
25.3 字符串输入输出
25.3.1 C 风格(printf / scanf / puts)
头文件 <stdio.h>
char str[] = "Hello World";
printf("%s\n", str); // %s 读到 '\0' 停止
puts(str); // 自动换行
scanf("%s", str) 遇空格/换行停止(不读空格);gets 已废弃(缓冲区溢出风险),禁用。
25.3.2 C++ cin / cout
#include <iostream>
using namespace std;
char input[20];
cin >> input; // 空格截断
cout << input << endl;
25.3.3 cin.getline 读取整行(含空格)
char line[50];
cin.getline(line, 50); // 最多读 49 字符,自动补 '\0'
25.4 C 字符串标准库函数(头文件 <cstring>)
25.4.1 strlen 求长度
统计有效字符,不含 \0。
char s[] = "Hello";
int len = strlen(s); // len = 5
25.4.2 strcpy 复制
把源串完整复制到目标(含 \0),目标空间必须充足。
char dest[20];
char src[] = "Copy me";
strcpy(dest, src);
25.4.3 strcat 拼接
把源串追加到目标末尾(覆盖原 \0,重补结束符)。
char dest[20] = "Hello";
char src[] = " World";
strcat(dest, src); // dest = "Hello World"
25.4.4 strcmp 比较
按 ASCII 逐字符比较:
s1 > s2:返回正数;- 相等:返回 0;
s1 < s2:返回负数。
int r1 = strcmp("apple", "banana"); // 负数('a'<'b')
int r2 = strcmp("hello", "hello"); // 0
25.4.5 strncmp 限定长度比较
仅比较前 n 个字符。
int r = strncmp("abcde", "abcfg", 3); // 前3位相等,返回 0
25.5 C++ string 类(头文件 <string>)
25.5.1 初始化
string s1; // 空串
string s2 = "Hello";
string s3(s2); // 拷贝
string s4(5, 'A'); // "AAAAA"
25.5.2 常用成员与运算符
string a = "Hi", b = " C++";
string c = a + b; // 拼接: "Hi C++"
a += b; // 追加
int len = a.length(); // 长度
bool e = a.empty(); // 是否空
char ch = a[0]; // 字符访问
bool eq = (a == b); // 直接比较
size_t pos = a.find("C++");// 找不到返回 string::npos
25.5.3 大小写转换(字符串实战)
string 没有内置 toupper,需配合 <cctype> 逐字符转换:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s = "Hello";
for (char &c : s) c = toupper(c); // 转大写 -> "HELLO"
cout << s << endl;
return 0;
}
string 自带长度管理、自动扩容、越界友好的 at(),比 C 字符数组安全得多。三级及以上竞赛优先用 string,仅在需要极高性能或与 C 接口交互时才用字符数组。
25.6 char 数组与 string 互转
string → C 风格指针:.c_str()
string s = "Test";
const char* p = s.c_str();
25.7 使用注意事项
- C 字符串必须以
\0结尾,库函数依赖结束符,缺失会乱码; strcpy、strcat必须保证目标数组容量足够;gets禁用,优先cin.getline/fgets;string更安全,竞赛推荐优先使用;getline读取前若有cin遗留换行,需清空缓冲区。
char buf[10]; strcpy(buf, "一个很长的字符串..."); 会越界写入,轻则崩溃,重则被利用。用 string 或 strncpy 并手动补 \0 更稳妥。
25.8 选择题练习
1. 关于 C 语言字符串,下列说法正确的是?
A. 字符串就是字符数组,二者完全等价
B. 字符串必须以 \0 作为结束标记
C. char a[3]={'a','b','c'}; 是合法字符串
D. strlen 统计的长度包含 \0
点击展开参考答案与解析
答案:B
解析:字符串是以 \0 结尾的字符数组,二者不等价(A 错);{'a','b','c'} 无 \0 不是字符串(C 错);strlen 不含 \0(D 错),选 B。
2. char s[] = "Hi";,数组 s 的实际长度是?
A. 2
B. 3
C. 1
D. 不确定
点击展开参考答案与解析
答案:B
解析:"Hi" 占 3 字节(H、i、\0),故 s 长度为 3,选 B。
3. 函数 strcmp("abc", "abd") 的返回值?
A. 0
B. 正数
C. 负数
D. 编译错误
点击展开参考答案与解析
答案:C
解析:逐字符比较:'a'==a,'b'==b,第三个 c(99) < d(100),故返回负数,选 C。
4. C++ string 类拼接两个字符串,应使用的运算符是?
A. &
B. +
C. *
D. ,
点击展开参考答案与解析
答案:B
解析:string 重载了 + 用于拼接,选 B。
5. 在 C++ 中把 string 转为 C 风格字符串,应调用?
A. .c_str()
B. .data()(仅某些场景)
C. .to_c()
D. .char_ptr()
点击展开参考答案与解析
答案:A
解析:.c_str() 返回 const char* 形式的 C 风格字符串,选 A。