字符串
名字、地址、商品编号……文字在程序里到处都是。C++ 用 std::string 放一串文字(要 #include <string>)。两个字符串用 + 就能接起来:
1#include <iostream>2#include <string>3 4int main() {5 std::string city = "上海";6 std::string street = "南京路";7 std::string address = city + street + " 100 号";8 std::cout << address << '\n';9 address += ",3 楼";10 std::cout << address << '\n';11 return 0;12}
上海南京路 100 号 上海南京路 100 号,3 楼
+ 把几段文字连成一个新字符串;+= 把一段文字接到原来那个的后面,和第 4 课里数字的 += 一个意思。
长度 size()
s.size() 告诉你字符串有多长。.size() 写在变量后面,是字符串自己带的成员函数,以后还会见到很多这样的写法。
1#include <iostream>2#include <string>3 4int main() {5 std::string code = "AB-1024";6 std::string name = "牛奶";7 std::cout << code.size() << '\n';8 std::cout << name.size() << '\n';9 return 0;10}
7 6
AB-1024 是 7 个字符,显示 7。可是「牛奶」两个字显示的是 6:size() 数的是字节,英文字母、数字、符号各占 1 个字节,一个汉字在这里占 3 个。所以这一课下面按位置取字符的例子都用英文和数字。
用下标取字符
字符串里的每个字符都有一个编号,叫下标,从 0 开始。s[0] 是第一个字符,s[s.size() - 1] 是最后一个。取出来的是 char。std::string 是可以改的:给 s[i] 赋值,就换掉了那个字符。
1#include <iostream>2#include <string>3 4int main() {5 std::string name = "jack";6 std::cout << name[0] << '\n';7 std::cout << name[name.size() - 1] << '\n';8 name[0] = 'J';9 std::cout << name << '\n';10 return 0;11}
j k Jack
点单步,看 name 从 jack 变成 Jack。注意 'J' 是单引号:name[0] 是一个字符,放进去的也得是一个字符。
下标越界
"AB12" 只有 4 个字符,下标是 0 到 3。用 s[10] 去取一个不存在的字符,是未定义行为:普通的电脑上可能显示一个乱七八糟的字符,也可能出别的事。我们的引擎会停在这一行:
1#include <iostream>2#include <string>3 4int main() {5 std::string code = "AB12";6 std::cout << code[3] << '\n';7 std::cout << code[10] << '\n';8 return 0;9}
2
index out of range发生了什么: 停在第 7 行:你访问了 string[10],可它只有 4 个字符(下标 0~3)。
code[3] 是最后一个字符 2,没问题;code[10] 越界了。(C++ 倒是允许读 code[4]:它是字符串结尾一个看不见的空字符,对你没什么用。)用下标之前,先想一想它是不是小于 size()。
substr 和 find
s.substr(start, n) 从下标 start 开始取 n 个字符,组成一个新字符串;不写 n 就一直取到最后。s.find("x") 找 x 第一次出现的下标。两个配起来,就能把一个邮箱拆成两半:
1#include <iostream>2#include <string>3 4int main() {5 std::string email = "[email protected]";6 auto at = email.find("@");7 std::cout << at << '\n';8 std::cout << email.substr(0, at) << '\n';9 std::cout << email.substr(at + 1) << '\n';10 return 0;11}
3 lin example.com
@ 在下标 3。substr(0, 3) 是前 3 个字符 lin,substr(4) 是从下标 4 到最后。find 返回的类型名字很长,这里正好用 auto。
找不到的时候,find 返回一个特别的值 std::string::npos(「没有这个位置」):
1#include <iostream>2#include <string>3 4int main() {5 std::string email = "lin.example.com";6 auto at = email.find("@");7 std::cout << (at == std::string::npos) << '\n';8 return 0;9}
1
显示 1,表示「是真的」:没找到。== 这一句外面要加括号,不然 << 会先算。第 6 课学了 if,就能写「找到了怎样,找不到怎样」。
比较字符串
== 看两个字符串是不是一模一样,< 和 > 按字典的顺序比,从第一个字符开始一个一个比:
1#include <iostream>2#include <string>3 4int main() {5 std::string a = "apple";6 std::string b = "banana";7 std::cout << (a == "apple") << '\n';8 std::cout << (a < b) << '\n';9 std::cout << ("Zoo" < a) << '\n';10 return 0;11}
1 1 1
三行都是 1。最后一行可能让你意外:比的是字符的编码,所有大写字母都排在小写字母前面,所以 Zoo 比 apple 小。汉字也是按编码比,不是按拼音或笔画。
这段程序显示什么?
1#include <iostream>2#include <string>3 4int main() {5 std::string a = "12";6 std::string b = "3";7 std::cout << a + b << '\n';8 return 0;9}
a 和 b 是字符串,不是数。字符串的 + 是把文字接起来:"12" 后面接上 "3",就是 "123"。
数字和字符串互换
要把数接进字符串,先用 std::to_string 把它变成字符串;反过来,std::stoi 把一串数字变成 int(i 是 int 的意思):
1#include <iostream>2#include <string>3 4int main() {5 int count = 3;6 std::string msg = "购物车里有 " + std::to_string(count) + " 件商品";7 std::cout << msg << '\n';8 std::string text = "42";9 int n = std::stoi(text);10 std::cout << n + 8 << '\n';11 return 0;12}
购物车里有 3 件商品 50
text + "8" 会是 "428";std::stoi(text) + 8 才是 50。从输入读到的、从文件里拿到的数字常常是字符串,算之前要先转换。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。
拼出全名
✓用 + 把 last 和 first 接起来,显示 林小明,你好!。
林小明,你好!
1#include <iostream>2#include <string>3 4int main() {5 std::string first = "小明";6 std::string last = "林";7 8 return 0;9}
邮箱里的用户名
✓用 find 和 substr 取出 @ 前面的部分,显示 用户名:zhang.wei。
用户名:zhang.wei
1#include <iostream>2#include <string>3 4int main() {5 std::string email = "[email protected]";6 7 return 0;8}
修好它:文字加数字
✓这段程序编译不过。改好它,让它显示 共 5 件。
共 5 件
1#include <iostream>2#include <string>3 4int main() {5 int count = 5;6 std::string msg = "共 " + count + " 件";7 std::cout << msg << '\n';8 return 0;9}
这一课学会了
std::string放一串文字;+把字符串接起来,+=接到后面。s.size()是字节数:英文字符各占 1 个,汉字在这里各占 3 个。s[i]取出下标i的字符,下标从 0 开始;字符串可以改:s[0] = 'J';。- 下标越界(
i不小于size())是未定义行为,引擎会停下。 s.substr(start, n)取一段;s.find("x")找位置,找不到是std::string::npos。==、<比较字符串,按字符的编码一个一个比,大写字母排在小写前面。std::to_string(n)把数变成字符串,std::stoi(s)把字符串变成int。