第六章:处理文字——字符串¶
你好!欢迎来到第六章!在前面的章节,我们学习了数字和数组。但生活中我们更多接触的是文字,比如名字、句子、文章。在C++中,文字数据叫做字符串。这一章我们会学习如何存储和操作字符串,包括古老的C风格字符串和更方便的C++ string 类。学完本章,你就能编写处理文字的程序了!
6.1 字符串程序范例¶
我们先来看一个简单的程序,它使用了C++中的 string 类型(最方便的一种字符串)。
#include <iostream>
#include <string> // 使用string需要包含这个头文件
using namespace std;
int main() {
string name; // 定义一个字符串变量,名字叫name
cout << "请输入你的名字:";
cin >> name; // 输入字符串(注意:不能有空格)
cout << "你好," << name << "!欢迎学习C++字符串!" << endl;
return 0;
}
运行示例(假设输入“小明”):
请输入你的名字:小明
你好,小明!欢迎学习C++字符串!
这个程序展示了字符串的基本输入输出。接下来我们会深入学习字符串的各种用法。
6.2 字符串的用法¶
6.2.1 字符的操作¶
字符串是由一个个字符组成的。在C++中,字符用 char 类型表示。我们先学会操作单个字符。
字符的定义和赋值¶
char ch1 = 'A'; // 单个字符用单引号括起来
char ch2 = 'b';
char ch3 = '5';
char ch4 = '!';
字符的输入输出¶
char ch;
cout << "请输入一个字符:";
cin >> ch; // 输入一个字符
cout << "你输入的字符是:" << ch << endl;
字符的ASCII码¶
每个字符在计算机中都有一个对应的整数编码,叫做ASCII码。例如 'A' 的ASCII码是65,'a' 是97,'0' 是48。字符可以和整数进行运算。
char ch = 'A';
cout << (int)ch << endl; // 输出65,将字符转为整数
cout << char(65) << endl; // 输出A,将整数转为字符
字符的运算¶
因为字符本质上是整数,所以可以进行加减运算。
char ch = 'A';
ch = ch + 1; // 变成 'B'
cout << ch << endl;
// 小写转大写
char lower = 'b';
char upper = lower - 32; // 因为小写字母比大写字母ASCII码大32
cout << upper << endl; // 输出'B'
常用字符判断(需要包含 <cctype> 头文件)¶
C++提供了许多判断字符类型的函数,非常方便。
| 函数 | 作用 |
|---|---|
isalpha(ch) |
判断是否是字母 |
isdigit(ch) |
判断是否是数字 |
islower(ch) |
判断是否是小写字母 |
isupper(ch) |
判断是否是大写字母 |
isspace(ch) |
判断是否是空格 |
tolower(ch) |
转换为小写 |
toupper(ch) |
转换为大写 |
#include <iostream>
#include <cctype> // 字符处理函数
using namespace std;
int main() {
char ch;
cout << "请输入一个字符:";
cin >> ch;
if (isalpha(ch)) {
cout << ch << " 是字母" << endl;
if (islower(ch)) {
cout << "它是小写字母,大写形式是:" << char(toupper(ch)) << endl;
} else {
cout << "它是大写字母,小写形式是:" << char(tolower(ch)) << endl;
}
} else if (isdigit(ch)) {
cout << ch << " 是数字" << endl;
} else {
cout << ch << " 是其他字符" << endl;
}
return 0;
}
6.2.2 字符数组¶
字符数组是C语言风格的字符串,就是用一个数组来存放多个字符,最后以 '\0' 结尾。
定义和初始化¶
char str1[10] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 手动加结束符
char str2[10] = "Hello"; // 自动在末尾加 '\0',最常用
char str3[] = "Hello"; // 编译器自动计算大小为6(包括'\0')
访问和遍历¶
char str[] = "Hello";
for (int i = 0; i < 5; i++) {
cout << str[i] << " "; // 输出 H e l l o
}
cout << endl;
// 也可以用while循环,直到遇到'\0'
int i = 0;
while (str[i] != '\0') {
cout << str[i];
i++;
}
修改字符数组中的元素¶
char str[] = "Hello";
str[0] = 'h'; // 修改第一个字符
cout << str; // 输出 "hello"
注意:字符数组的大小一旦定义就不能改变,所以要保证足够大。
6.2.3 字符串的输入和输出¶
C风格字符串的输入¶
- 用
cin >>输入,但遇到空格会停止。 - 用
cin.getline()可以输入带空格的整行。
#include <iostream>
using namespace std;
int main() {
char name[50];
cout << "请输入你的名字(无空格):";
cin >> name; // 只能输入一个单词
cout << "你好," << name << endl;
// 清空输入缓冲区(因为后面要用getline,之前cin会留下换行符)
cin.ignore();
char sentence[100];
cout << "请输入一句话(可带空格):";
cin.getline(sentence, 100); // 读取整行,最多99个字符
cout << "你输入的是:" << sentence << endl;
return 0;
}
string类的输入¶
- 用
cin >>输入,同样遇空格停止。 - 用
getline(cin, 字符串变量)输入整行。
#include <iostream>
#include <string>
using namespace std;
int main() {
string name, sentence;
cout << "请输入你的名字:";
cin >> name;
cout << "你好," << name << endl;
cin.ignore(); // 忽略输入缓冲区中的换行符
cout << "请输入一句话:";
getline(cin, sentence); // 读取整行
cout << "你输入的是:" << sentence << endl;
return 0;
}
6.2.4 字符串结束符‘\0’¶
C风格字符串以 '\0'(空字符,ASCII码0)作为结束标志。它告诉程序字符串在哪里结束。
为什么需要 '\0'?¶
因为字符数组的长度可能大于字符串的实际长度,如果没有结束符,程序就不知道到哪里是字符串的结尾。比如:
char str[10] = "Hello"; // 实际存储:H e l l o \0 ? ? ? ?
当输出 str 时,函数会从第一个字符开始一直输出直到遇到 '\0'。如果忘了加 '\0',可能会输出乱码直到遇到内存中的某个0。
手动添加 '\0'¶
如果自己逐个字符赋值,必须手动加上 '\0'。
char str[5];
str[0] = 'C';
str[1] = '+';
str[2] = '+';
str[3] = '\0'; // 必须加!
cout << str; // 输出 "C++"
如果忘记加,cout 会继续向后输出内存中的内容,直到偶然遇到0,可能导致程序崩溃或输出乱码。
6.2.5 字符串常用函数¶
C语言提供了一些处理字符串的函数,它们定义在 <cstring> 头文件中。注意这些函数都用于C风格字符串(字符数组)。
| 函数 | 作用 |
|---|---|
strlen(s) |
返回字符串s的长度(不包括\0) |
strcpy(dest, src) |
将src复制到dest |
strcat(dest, src) |
将src连接到dest的末尾 |
strcmp(s1, s2) |
比较s1和s2,相等返回0,s1 |
strchr(s, c) |
在s中查找字符c第一次出现的位置,返回指针 |
strstr(s1, s2) |
在s1中查找子串s2,返回指针 |
示例代码¶
#include <iostream>
#include <cstring> // 字符串函数
using namespace std;
int main() {
char s1[20] = "Hello";
char s2[20] = "World";
char s3[40];
// 求长度
cout << "s1长度:" << strlen(s1) << endl; // 5
// 复制
strcpy(s3, s1); // s3 = "Hello"
cout << "s3 = " << s3 << endl;
// 连接
strcat(s3, " "); // 加一个空格
strcat(s3, s2); // s3 = "Hello World"
cout << "连接后:" << s3 << endl;
// 比较
if (strcmp(s1, s2) == 0) {
cout << "s1和s2相等" << endl;
} else {
cout << "s1和s2不相等" << endl;
}
return 0;
}
注意:使用这些函数时,要确保目标数组足够大,否则会溢出。
6.2.6 string类¶
C++提供了一个更安全、更方便的字符串类型:string。它包含在头文件 <string> 中。使用 string 类可以像普通变量一样操作字符串,不需要担心数组大小和结束符。
定义和初始化¶
#include <string>
string s1; // 空字符串
string s2 = "Hello"; // 直接赋值
string s3("World"); // 构造函数
string s4 = s2; // 复制
string s5 = s2 + " " + s3; // 连接
常用操作¶
- 长度:
s.length()或s.size() - 访问字符:
s[i],下标从0开始 - 赋值:
s = "new value"; - 连接:用
+或+= - 比较:直接用
==、!=、<、>等运算符 - 输入:
cin >> s或getline(cin, s) - 输出:
cout << s
示例代码¶
#include <iostream>
#include <string>
using namespace std;
int main() {
string s1 = "Hello";
string s2 = "World";
string s3;
// 连接
s3 = s1 + " " + s2;
cout << "s3 = " << s3 << endl; // Hello World
// 长度
cout << "s3的长度:" << s3.length() << endl; // 11
// 访问字符
for (int i = 0; i < s3.length(); i++) {
cout << s3[i] << " "; // H e l l o W o r l d
}
cout << endl;
// 比较
if (s1 == s2) {
cout << "相等" << endl;
} else {
cout << "不相等" << endl;
}
// 子串
string sub = s3.substr(6, 5); // 从下标6开始取5个字符
cout << "子串:" << sub << endl; // World
// 查找
int pos = s3.find("World");
if (pos != string::npos) {
cout << "找到World,位置在:" << pos << endl;
}
return 0;
}
string类的更多成员函数¶
s.substr(pos, len):返回从pos开始长度为len的子串。s.find(str):查找子串,返回第一次出现的位置,如果找不到返回string::npos。s.replace(pos, len, str):将从pos开始长度为len的子串替换为str。s.insert(pos, str):在pos位置插入str。s.erase(pos, len):删除从pos开始的len个字符。s.empty():判断是否为空。s.clear():清空字符串。
6.2.7 阶段性编程练习(字符串基础)¶
- 练习1:输入一个字符,判断它是字母、数字还是其他字符,并输出对应信息。
- 练习2:输入一行字符串(可含空格),统计其中字母、数字、空格的个数。
- 练习3:输入一个字符串,将其中的小写字母转为大写,大写字母转为小写,其他字符不变,输出结果。
- 练习4:用C风格字符串实现字符串反转(不使用string类的reverse函数)。
- 练习5:用string类实现:输入两个字符串,连接后输出,并输出长度。
6.3 编程实例讲解¶
这里我们通过几个综合实例,进一步巩固字符串的操作。
实例1:统计单词个数(使用string)¶
题目:输入一行英文句子,统计其中有多少个单词(单词之间用空格分隔)。
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cout << "请输入一句英文:";
getline(cin, s); // 读取整行
int count = 0;
bool inWord = false; // 标记是否正在一个单词中
for (int i = 0; i < s.length(); i++) {
if (s[i] != ' ') { // 如果当前字符不是空格
if (!inWord) { // 并且之前不在单词中,说明新单词开始
count++;
inWord = true;
}
} else { // 遇到空格,表示单词结束
inWord = false;
}
}
cout << "单词个数:" << count << endl;
return 0;
}
实例2:判断回文串¶
题目:输入一个字符串(忽略空格和标点,只考虑字母和数字),判断它是否是回文(正读反读一样,比如 “madam”、”12321”)。
#include <iostream>
#include <string>
#include <cctype> // 字符处理函数
using namespace std;
int main() {
string s;
cout << "请输入一个字符串:";
getline(cin, s);
// 先过滤掉非字母数字字符,并转为小写
string filtered;
for (int i = 0; i < s.length(); i++) {
if (isalnum(s[i])) { // 如果是字母或数字
filtered += tolower(s[i]); // 转为小写后加入
}
}
// 判断回文
bool isPalindrome = true;
int len = filtered.length();
for (int i = 0; i < len / 2; i++) {
if (filtered[i] != filtered[len - 1 - i]) {
isPalindrome = false;
break;
}
}
if (isPalindrome) {
cout << "是回文" << endl;
} else {
cout << "不是回文" << endl;
}
return 0;
}
实例3:凯撒密码(加密)¶
题目:输入一个字符串和一个偏移量k,将字符串中的每个英文字母替换为字母表中后移k位的字母(循环,例如z后移1位变成a),其他字符不变,输出加密后的字符串。
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
int k;
cout << "请输入要加密的字符串:";
getline(cin, s);
cout << "请输入偏移量:";
cin >> k;
for (int i = 0; i < s.length(); i++) {
char ch = s[i];
if (ch >= 'a' && ch <= 'z') {
ch = 'a' + (ch - 'a' + k) % 26;
} else if (ch >= 'A' && ch <= 'Z') {
ch = 'A' + (ch - 'A' + k) % 26;
}
s[i] = ch;
}
cout << "加密后的字符串:" << s << endl;
return 0;
}
实例4:字符串排序(按字典序)¶
题目:输入若干个人名(字符串),按字典序从小到大排序后输出。
#include <iostream>
#include <string>
using namespace std;
int main() {
const int N = 5;
string names[N];
cout << "请输入" << N << "个人名:" << endl;
for (int i = 0; i < N; i++) {
cin >> names[i]; // 假设名字不含空格
}
// 冒泡排序
for (int i = 0; i < N - 1; i++) {
for (int j = 0; j < N - 1 - i; j++) {
if (names[j] > names[j + 1]) { // string可以直接比较
string temp = names[j];
names[j] = names[j + 1];
names[j + 1] = temp;
}
}
}
cout << "排序后的名字:" << endl;
for (int i = 0; i < N; i++) {
cout << names[i] << endl;
}
return 0;
}
6.4 第6章编程作业¶
恭喜你学完了字符串!现在来挑战几个综合题目,检验一下学习成果。
作业1:统计字符串中每个字母出现的次数¶
输入一行字符串(可含空格),统计其中26个英文字母(不区分大小写)各自出现的次数,并输出。忽略非字母字符。
作业2:简单密码验证¶
设定一个密码字符串(如 “C++2024”),让用户输入密码,最多允许输入3次,如果正确显示“欢迎”,否则显示“密码错误”并提示剩余次数,3次错误后显示“账户锁定”。
作业3:手机键盘数字映射¶
在老式手机键盘上,字母映射到数字:2:abc, 3:def, 4:ghi, 5:jkl, 6:mno, 7:pqrs, 8:tuv, 9:wxyz。输入一个单词(只含字母),输出对应的数字串。例如输入 “hello”,输出 “43556”。
作业4:字符串去重¶
输入一个字符串,去掉其中重复的字符(只保留第一次出现的字符),输出结果。例如输入 “hello world”,输出 “helo wrd”(注意空格也要保留,但重复的空格只保留一个?可以自己定义规则)。
作业5:单词反转¶
输入一句英文,将句子中的单词顺序反转,但单词内部的字母顺序不变。例如输入 “I love C++”,输出 “C++ love I”。提示:可以用字符串流或手动分割单词。