字符类型
字符类型(Character type)变量,顾名思义是用来存储字符的变量。它也包括许多分类,不过我们只需要掌握其中一种就够了。这一种就是之前提到过的 char 型变量。
char 型变量是用于存储部分字符的变量。这部分字符被称作 ASCII 字符,它包括不可见字符和可见字符两部分,共 128 个。除了这 128 个字符之外的字符一般不能用 char 型变量来存储。其中:
- 不可见字符 33 个,包括换行、Tab(制表符)、退格、删除和响铃等控制字符。
- 可见字符 95 个,包括大小写字母、数字和常见符号等打印字符。
可见字符顾名思义是“可以看见”的字符。这些字符主要的作用是供读者阅读:比如 A p p l e 这五个字符共同组成了 Apple 这个单词,然后读者可以理解它的意思。不可见字符则是“不可以看见”的字符。有读者可能奇怪,不能看见的字符有什么用呢?其实它的作用主要是控制计算机的除了阅读外的一些其它功能:比如“换行字符”可以让控制台的光标移动到下一行,“响铃字符”可以让计算机发出一个声音等等。
可见字符可以用单引号引起的方式表示出来。比如
char at{'@'};
定义了一个名为 at 的字符型变量,它的初始化值是 '@' ,也就是目前存储了 @ 这个字符。
存储细节
C++标准规定 char 型的大小为 1 字节。这就是为什么有的时候 char 就是字节类型的同义词。
常识告诉我们,计算机中只能存储二进制数,不能直接存储一个字符。所以计算机采用了 ASCII 码表来实现字符到数的对应。比如:
- ' '(空格)对应 20
- '0'(字符 0)对应 48
- '1'(字符 1)对应 49
- ……
- '@'对应 64
- 'A'对应 65
- 'B'对应 66
- ……
- 'Z'对应 90
- 'a'对应 97
- 'b'对应 98
- ……
等等。有时我们称字符所对应的数为这个字符的ASCII码。完整的ASCII码表可以参见书后附录,我们不需要特别记忆它。
我们已经知道了如何将一些可见字符赋值给字符类型,那么如何将不可见字符——比如换行符赋给字符类型呢?又如何使用单引号 ' 和双引号 " 却不引起歧义呢?这时需要使用转义字符这个概念。转义字符(Escaped character)是以反斜杠 '\' 开头的字符。反斜杠及其后面的字符将作为一个整体代表一个新的含义的字符。比如,我们使用 '\n' 表示换行符,使用 '\t' 表示制表符。可能的转义字符在下表列出:
| 转义字符 | 描述 | 表示 | 
|---|---|---|
| \' | 单引号 | ASCII 编码中为字节 0x27 | 
| \" | 双引号 | ASCII 编码中为字节 0x22 | 
| \? | 问号 | ASCII 编码中为字节 0x3f | 
| \\ | 反斜杠 | ASCII 编码中为字节 0x5c | 
| \a | 响铃 | ASCII 编码中为字节 0x07 | 
| \b | 退格 | ASCII 编码中为字节 0x08 | 
| \f | 换页 | ASCII 编码中为字节 0x0c | 
| \n | 换行 | ASCII 编码中为字节 0x0a | 
| \r | 回车 | ASCII 编码中为字节 0x0d | 
| \t | 水平制表 | ASCII 编码中为字节 0x09 | 
| \v | 垂直制表 | ASCII 编码中为字节 0x0b | 
| \nnn | 任意八进制值 | 字节 nnn | 
| \xnn | 任意十六进制值 | 字节 nn | 
同样地,转义字符也可以作为“一句话”的一部分出现在双引号内。下面是一个使用转义字符的例子:
它的编译运行结果为(并可能响铃一次):
This is the first line!
\
"'"
响铃与否取决于你使用的终端。如果直接在终端运行的话,Windows 10 会发出“噔咚咚”的响铃;macOS 可能会发出“嘟”的一声。
你可能已经注意到了,字符型和布尔型都属于整数类型的范畴。因此它们都可以像整数那样进行计算如加法、减法等:比如 'A' + 1 的结果就是 'B' 。下面这个例子简单演示了字符类型的运算:
它的运算结果如下,你可以对照 ASCII 码表进行验证:
@ 90
26 m
实际上,
char类型也区分signed与unsigned。但是你可以发现它们的取值范围分别是 -128 ~ 127 和 0 256;其中都覆盖了 ASCII 码表的取值范围(0 ~ 127)。因此在存储 ASCII 字符时,char的有无符号性是没有影响的。
总结
至此我们已经将 C++ 的最基础的类型——算术类型讲解完毕了。下面这张表大致地总结了它们:
| 类型说明符 | 含义 | 一般的字节数 | 一般的取值范围 | |
|---|---|---|---|---|
| signed | unsigned | |||
| bool | 布尔类型 | 1 | true或false | |
| char | 字符类型 | 1 | ASCII 字符 | |
| short | 短整型 | 2 | ~ | ~ | 
| int | 整型 | 4 | ~ | ~ | 
| long※ | 长整型 | 4 | ~ | ~ | 
| long long | 扩展长整型 | 8 | ~ | ~ | 
| float | 单精度浮点型 | 4 | 6~7 位有效数字 | |
| double | 双精度浮点型 | 8 | 15~16 位有效数字 | |
| long double | 扩展精度浮点型 | 8 | 不少于 15 位有效数字 | |
※ 在 64 位的 UNIX 或类 UNIX 系统下, long 占用 8 字节,表示范围与 long long 相同。
练习
- 仿照上一章的“猜数游戏”,编写一个“猜字母”的游戏:程序指定一个大写字母,允许用户通过多次输入来猜测是哪一个字母,直至猜对为止。猜错的提示与“猜数游戏”相同,输出提示是猜“大”了还是“小”了。(提示: char型变量仍然可以通过大于、小于号进行比较。)
练习参考答案
#include <iostream>
using namespace std;
int main() {
    char ans{'G'}; // 答案
    char x{'A'};   // 这里不写初始化器也没有问题。
    cin >> x;
    while (x != ans) {
        if (x > ans) {
            cout << "That's bigger than the answer. Try again?" << endl;
        }
        if (x < ans) {
            cout << "That's smaller than the answer. Try again?" << endl;
        }
        cin >> x;
    }
    cout << "Bingo! You got the answer!" << endl;
}