c++语法——字符串(10.23讲课)
声明:本节课涉及一些原理性知识,比较难理解
但是大家要知道,咱现在学的是c++语法,是人为规定的东西,不要过多的思考为什么这样写,为什么这样定义,那个人就是这么规定的!!!以后大家如果有能力可以自己规定一个自己的语言
在编程中,我们经常需要处理文本信息—— 比如用户输入的名字、程序输出的提示语、读取的文档内容等。而 “字符” 是文本的最小单位(如 'a'、'1'、'+'),“字符串” 是字符的组合(如 "Hello"、"C++2024"),ASCII 码则是字符与计算机底层数字的 “翻译桥梁”。
掌握这三部分知识,是实现文本输入输出、判断字符类型(大写 / 小写 / 数字)、字符串拼接 / 截取等功能的基础,也是后续做编程题(如 “统计单词个数”“密码合法性判断”)的核心能力。
目录
代码规范问题
1.命名规范
2.缩进规范(编译器会自动缩进)
3.大括号问题
回顾数组
字符类型(char)与 ASCII 码表
一 ·字符类型(char)
二·ASCII 码表
1·是什么以及为什么
2·核心规律(做题必用):
四个问题
输入一个小写字符,输出它对应的大写字符
输出一个大写字符,输出它对应的小写字符
输入一个字符,判断字符是否是小写字母,如果是输出“YES”否则输出“NO”
输入两个字符数字,计算两个字符对应数字的加和
3·ASCII 码的做题应用示例
示例 1:判断字符是否为大写字母
示例 2:小写字母转大写字母
三·字符串(string)
1·string 类的基本使用:定义与初始化
2·读写 string 操作
1·一般读入
2·读入整行带空格的字符串
3·下标访问字符串中的元素
4·拼接、比较等操作
字典序
5·字符串的遍历
6·string常用操作(初学阶段不要求掌握,有印象即可)
练习
代码规范问题
xcpc比赛是三人组队赛,代码不光要自己能看懂,还要让队友也能看懂,所以代码规范很重要!!!
1.命名规范
普通变量尽量使用a,b,c等小写字母,不要用大写字母,可以节省一些时间
尽量不要在变量名中使用-/等字符,不方便敲,也不好看
约定俗成的一些命名规范(便于明确变量意义)
循环 i-j-k(从内到外)
for (int i = 1; i <= n; i++) {for (int j=1;j<=n;j++) {for (int k=1;k<=n;k++) {}}}
总和 sum1,sum2......
计数 cnt1,cnt2.......
2.缩进规范(编译器会自动缩进)
3.大括号问题
选择语句和循环语句虽然在语句只有一句的时候可以省略大括号,但是不推荐省略,容易出错,并且看起来看不直观
回顾数组
B2098 整数去重https://www.luogu.com.cn/problem/B2098
字符类型(char)与 ASCII 码表
一 ·字符类型(char)
语法格式:定义字符变量时,字符常量必须用单引号 '字符' 包裹(双引号是字符串专用,注意区分!)
// 正确:单引号包裹单个字符char ch1 = 'A'; char ch2 = '5'; char ch3 = ' '; // 空格也是一个字符(很重要!)// 错误:双引号是字符串,不能给char赋值// char ch4 = "B"; // 输出字符cout << "ch1 = " << ch1 << endl; // 输出:ch1 = A
#include<bits/stdc++.h>
using namespace std;
int main() {char b='b';char a=b;cout << a;
}
输出:b
二·ASCII 码表
1·是什么以及为什么
关键:char 本质是 “存储 ASCII 码”
计算机只能识别二进制数字,无法直接存储 “字符”。因此,人们约定了一套规则:给每个常用字符分配一个唯一的十进制数字,这套规则就是ASCII 码表(American Standard Code for Information Interchange)。
char 变量存储的不是 “字符本身”,而是该字符对应的ASCII 码值
不需要背诵完整 ASCII 码表,但以下几类必须记牢,直接关系到做题效率(记不住没关系直接用编译器通过强制转换就能直接得到对应字符的ASCII值):
数字字符('0'-'9') | 48-57 | '0' 是 48,'1' 是 49,…,'9' 是 57 |
大写字母('A'-'Z') | 65-90 | 'A' 是 65,'B' 是 66,…,'Z' 是 90 |
小写字母('a'-'z') | 97-122 | 'a' 是 97,'b' 是 98,…,'z' 是 122 |
我们可以通过强制类型转换,看到字符对应的 ASCII 码:
#include <iostream>
using namespace std;int main() {char ch = 'A';// 输出字符:A;强制转int后输出ASCII码:65cout << "字符:" << ch << ",ASCII码:" << (int)ch << endl; return 0;
}
// 运行结果:字符:A,ASCII码:65
2·核心规律(做题必用):
- 大小写字母转换:小写字母 ASCII 码 = 大写字母 ASCII 码 + 32例:'A'(65)+32 = 'a'(97),'z'(122)-32 = 'Z'(90)
- 字符数字转整数:字符 '0'-'9' 转整数时,需减去 '0' 的 ASCII 码(48)例:'5'(53)-48 = 5(整数),'9'(57)-48 = 9(整数)
四个问题
输入一个小写字符,输出它对应的大写字符
输出一个大写字符,输出它对应的小写字符
输入一个字符,判断字符是否是小写字母,如果是输出“YES”否则输出“NO”
输入两个字符数字,计算两个字符对应数字的加和
#include<bits/stdc++.h>
using namespace std;
int main() {char b='2';int a=b-'0';cout << a;
}
输出:2
#include<bits/stdc++.h>
using namespace std;
int main() {char b='2';int a=b;cout << a;
}
输出:50
3·ASCII 码的做题应用示例
示例 1:判断字符是否为大写字母
题目:输入一个字符,判断它是否是大写字母(是则输出 “YES”,否则输出 “NO”)。思路:利用大写字母 ASCII 码范围(65~90),或直接用字符比较('A'~'Z')。
#include<bits/stdc++.h>
using namespace std;
int main() {char ch;cin >> ch;// 方法1:用ASCII码范围判断if (ch >= 65 && ch <= 90) {cout << "YES" << endl;} else {cout << "NO" << endl;}// 方法2:用字符直接比较(更直观,推荐)// if (ch >= 'A' && ch <= 'Z') {// cout << "YES" << endl;// } else {// cout << "NO" << endl;// }return 0;
}
示例 2:小写字母转大写字母
题目:输入一个小写字母,将其转换为大写字母并输出。思路:利用 “小写 = 大写 +32” 的逆运算(大写 = 小写 -32)。
#include<bits/stdc++.h>
using namespace std;int main() {char lower_ch;cin >> lower_ch;// 先判断是否为小写字母(避免输入错误)if (lower_ch >= 'a' && lower_ch <= 'z') {char upper_ch = lower_ch - 32; // 转换核心cout << "大写字母:" << upper_ch << endl;} else {cout << "输入不是小写字母!" << endl;}return 0;
}
// 输入:a → 输出:大写字母:A
// 输入:B → 输出:输入不是小写字母!
三·字符串(string)
字符串是 “多个字符的有序集合”,C++ 中有两种字符串表示方式:
- C 风格字符串:用
char数组
存储,需以'\0'
(空字符,ASCII 码 0)结尾(容易出错,新手先重点学 string);(不用在意) - C++ string 类:STL(标准模板库)提供的字符串类,封装了常用操作(无需手动管理
'\0'
,但是最后还是会有‘\0’,安全易用,做题首选)。
1·string 类的基本使用:定义与初始化
string s1; // 定义一个空字符串string s2 = s1; //用s1初始化s2string s3 = "hello world"; // 初始化s3为 "hello world" string s4(6,'a'); // 初始化s4为:aaaaaastring s5(s6, 3); // s5 是从 s4 的下标 3 开始的字符拷贝string s6(s6, pos, len); // s6 是从 s5 的下标 pos 开始的 len 个字符的拷贝
#include<bits/stdc++.h>
using namespace std;
int main() {string a="aaaaaa";string b(a,3);string c(a,3,2);cout << b << endl << c << endl;
}
2·读写 string 操作
1·一般读入
#include<bits/stdc++.h>
using namespace std;
int main() {string s1, s2, s3; // 初始化一个空字符串// 单字符串输入,读入字符串,遇到空格或回车停止cin >> s1; // 多字符串的输入,遇到空格代表当前字符串赋值完成,转到下个字符串赋值,回车停止cin >> s2 >> s3; // 输出字符串 cout << s1 << endl; cout << s2 << endl;cout << s3 << endl;
}
2·读入整行带空格的字符串
getline(cin , 字符串名);
string s1 ; // 初始化一个空字符串getline(cin , s1); cout << s1 << endl; // 输出
3·下标访问字符串中的元素
#include<bits/stdc++.h>
using namespace std;
int main() {string a="abcd";string b(a,3);string c(a,3,2);cout << a[0] << ' ' << a[1] << ' ' << a[2] << ' ' << a[3] ;
}
下标从0开始,但是字符串实际长度会多一,因为有'\0'
但这样仍能运行不会编译错误,因为string的长度不是固定的
比如:
#include<bits/stdc++.h>
using namespace std;
int main() {string a="abcd";a+="ef";cout << a[0] << ' ' << a[1] << ' ' << a[2] << ' ' << a[3] << ' ' << a[4] << ' ' << a[5];
}
这就涉及到了拼接、比较等操作
4·拼接、比较等操作
s1+s2 // 返回 s1 和 s2 拼接后的结果。
s1 == s2 // 如果 s1 和 s2 中的元素完全相等则它们相等,区分大小写
s1 != s2
<, <=, >, >= // 利用字符的字典序进行比较,区分大小写
5·字典序
在字典中,单词是按照首字母在字母表中的顺序进行排列的,比如 alpha 在 beta 之前。而第一个字母相同时,会去比较两个单词的第二个字母在字母表中的顺序,比如 account 在 advanced 之前,以此类推。
在字符串处理中,“字典序”(Lexicographical Order)是一种模仿字典中单词排列规则的字符串比较方式,是字符串排序、比较的核心依据。理解字典序对处理字符串排序、判断大小等问题至关重要。
一、什么是字典序?
字典序本质是字符逐个比较的规则,类似我们查字典时确定单词先后顺序的方式:
- 先比较两个字符串的第一个字符,ASCII 码小的字符串在前;
- 若第一个字符相同,则比较第二个字符,以此类推;
- 若一个字符串是另一个字符串的前缀(如 "app" 和 "apple"),则长度短的字符串在前。
核心依据:字符的 ASCII 码值(字符的 “大小” 由其 ASCII 码决定)。
二、字典序的具体比较规则(示例说明)
假设比较字符串 s1
和 s2
:
-
逐个字符比较:
-
例 1:
s1 = "apple"
,s2 = "banana"
第一个字符'a'
(ASCII 97) <'b'
(ASCII 98)→ 故s1 < s2
(s1
在前)。 -
例 2:
s1 = "cat"
,s2 = "car"
前两个字符相同('c'
、'a'
),比较第三个字符:'t'
(116) >'r'
(114)→ 故s1 > s2
(s2
在前)。
-
-
前缀关系:
- 例 3:
s1 = "app"
,s2 = "apple"
s1
是s2
的前缀(前 3 个字符完全相同),且s1
更短 → 故s1 < s2
(s1
在前)。
- 例 3:
-
空字符串:
- 空字符串(
""
)是所有非空字符串的前缀 → 空字符串 < 任何非空字符串。
- 空字符串(
三、C++ 中如何使用字典序比较字符串?
C++ 的 string
类已重载了比较运算符(==
、!=
、<
、>
、<=
、>=
),直接按照字典序进行比较,无需手动实现。
#include<bits/stdc++.h>
using namespace std;
int main() {string a="ab",b="bb";if (a>b) {cout << 1 << endl;}else if (a==b){cout << 2 << endl;}else {cout << 3 << endl;}a="ab",b="ab";if (a>b) {cout << 1 << endl;}else if (a==b){cout << 2 << endl;}else {cout << 3 << endl;}a="ac",b="ab";if (a>b) {cout << 1 << endl;}else if (a==b){cout << 2 << endl;}else {cout << 3 << endl;}
}
6·字符串的遍历
#include<bits/stdc++.h>
using namespace std;
int main() {string a="ab",b="bb";cout << a.size();
}
#include<bits/stdc++.h>
using namespace std;
int main() {string s = "abcdef";// 用 size() 控制循环范围,遍历每个字符for (int i = 0; i < s.size(); i++) { // i < s.size() 确保不越界cout << "第" << i << "个字符:" << s[i] << endl;}return 0;
}// 输出:
// 第0个字符:a
// 第1个字符:b
// 第2个字符:c
// 第3个字符:d
// 第4个字符:e
// 第5个字符:f
7·string常用操作(初学阶段不要求掌握,有印象即可)
s.size() 返回字符串的长度(不含'\0')
s.erase(pos, len) 删除从 pos 开始的 len 个字符。如果 len 省略,则删除 pos 开始的后面所有字符。返回一个指向 s 的引用。
s.find(args) 查找 s 中 args 第一次出现的位置
s.rfind(args) 查找 s 中 args 最后一次出现的位置
to_string(val) 将数值 val 转换为 string 并返回。val 可以是任何算术类型(int、浮点型等)
s.substr(pos, n) 从索引 pos 开始,提取连续的 n 个字符,包括 pos 位置的字符
reverse(s2.begin(), s2.end()) 反转 string 定义的字符串 s2 s.insert(pos, args) 在 pos 之前插入 args 指定的字符
练习
B2109 统计数字字符个数https://www.luogu.com.cn/problem/B2109
B2115 密码翻译https://www.luogu.com.cn/problem/B2115
B2112 石头剪子布https://www.luogu.com.cn/problem/B2112
B2120 单词的长度https://www.luogu.com.cn/problem/B2120
B2110 找第一个只出现一次的字符https://www.luogu.com.cn/problem/B2110