Skip to content

字符类型

字符型变量用于存储一个单一字符,在 C 语⾔中用 char 表示,其中每个字符变量都会占用 1个字节。在给字符型变量赋值时,需要用一对英文半角格式的单引号(' ')把字符括起来。

字符变量实际上并不是把该字符本⾝放到变量的内存单元中去,而是将该字符对应的 ASCII 编码放到变量的存储单元中。

不同的机器可能使用不同的字符集,因此 char 类型的值也可能根据计算机的不同而不 同。不过,当今使用最广泛的字符集是 ASCII (American Standard Code for Information Interchange) 字符集,它已成为事实上的标准。ASCII 字符集使用 7 位来 表示 128 个字符,如下图所示:

ASCII 码⼤致由以下两部分组成:

  • ASCII 非打印控制字符: ASCII 表上的数字 0-31 分配给了控制字符,用于控制像打印机等一些外围设备。
  • ASCII 打印字符:数字 32-126 分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。数字 127 代表 Del 命令。

其中有几个字符的数值是需要记住的:' ' = 32, '0' = 48, 'A' = 65, 'a' = 97。

char 类型的变量可以存储单个字符,注意:字符字面值应该用单引号括起来。

cpp
char ch;

ch = 'a';
ch = 'A';
ch = '0';
ch = ' ';

字符操作

,毕竟字符和整数之间的关联是非常强的。

当计算中出现字符时,C 语言会使用字符对应的整数值,如:

cpp
char ch;
int i;

i = 'a';    // is is now 97
ch = 65;    // ch is now 'A'
ch = ch +1; // ch is now 'B'
ch++;       // ch is now 'C'

我们也可以像比较整数那样对字符进行比较。比如,下面的代码可以把小写字母变成大写字母。

cpp
/* not commended, toupper function is better */
if (ch >= 'a' && ch <= 'z')
    ch = ch - 'a' + 'A';

我们还可以像下面这样使用 for 循环遍历所有的大写字母:

cpp
for (ch = 'A'; ch <= 'Z'; ch++) ...

把字符当作整数来处理,可以给我们带来方便,但也可以导致我们写出一些无意义的表达式:

cpp
'a' * 'b' / 'c';    /* Don't do this */
字符变量定义与输出示例
c
#include <stdio.h>
#include <stdlib.h>

int main() {
    char ch = 'a';
    printf("sizeof(ch) = %zu\n", sizeof(ch));
    printf("ch[%%c] = %c\n", ch);//打印字符
    printf("ch[%%d] = %d\n", ch);//打印‘a’ ASCII的值

    char A = 'A';
    char a = 'a';
    printf("a = %d\n", a);       //97
    printf("A = %d\n", A);       //65
    printf("A = %c\n", 'a' - 32);//小写a转⼤写A
    printf("a = %c\n", 'A' + 32);//⼤写A转小写a

    ch = ' ';
    printf("空字符:%d\n", ch);   //空字符ASCII的值为32
    printf("A = %c\n", 'a' - ' ');//小写a转⼤写A
    printf("a = %c\n", 'A' + ' ');//⼤写A转小写a

    return 0;
}

程序输出:

shell
sizeof(ch) = 1
ch[%c] = a
ch[%d] = 97
a = 97
A = 65
A = A
a = a
空字符:32
A = A
a = a

转义序列

正如我们前面看到的,有些字符我们是无法从键盘上直接输入的,比如一些控制字符和空白字符。为了让程序能够处理字符集中的每一个字符,C 语言提供了字符的一种特殊表示方式——转义序列 (Escape Sequences)。

转义序列分为两种:字符转义序列和数字转义序列。前面我们已经见过了一些字符转义序列,下表给出了字符转义序列的完整集合:

转义字符含义ASCII码值(十进制)
警报007
退格(BS) ,将当前位置移到前一列008
换页(FF),将当前位置移到下页开头012
换行(LF) ,将当前位置移到下一行开头010
回车(CR) ,将当前位置移到本行开头013
⽔平制表(HT) (跳到下一个TAB位置)009
垂直制表(VT)011
\\代表一个反斜线字符"\092
\'代表一个单引号(撇号)字符039
\"代表一个双引号字符034
\?代表一个问号063
\0数字0000
\ddd8进制转义字符,d范围0~73位8进制
\xhh16进制转义字符,h范围09,af,A~F3位16进制

注意:红⾊字体标注的为不可打印字符。

字符转义序列使用起来是很方便的,但是它有一个问题:字符转义序列没有包含所有 的不可打印的 ASCII 字符,而且它也不能表示 ASCII 以外的字符。

数字转义序列可以解决上面的问题,它可以表示任意一个字符。我们可以使用八进制 或者十六进制来书写数字转义序列。

  • 八进制转义序列由 \ 和一个最多 3 位的八进制数字组成。比如 ESC 的编码为 27, 用八进制表示就是 33,因此它可以表示成 \33 或者 \033。注意,和八进制整数不 一样的是,转义字符中的八进制数不需要以 0 开头。
  • 十六进制转义序列由 \x 和一个十六进制数组成。比如 ESC 字符也可以写成 \x1b\x1B 的形式。其中 x 必须小写,但是十六进制数字不限大小写。

当转义序列作为字符常量使用时,必须用一对单引号括起来。比如:`\n', '\33' 或 '\x1B'。

编写代码测试
c
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("abc");
    printf("\refg\n");//\r切换到句⾸, \n为换行键

    printf("abc");
    printf("\befg\n");//\b为退格键, \n为换行键

    printf("%d\n", '\123');// '\123'为8进制转义字符,0123对应10进制数为83
    printf("%d\n", '\x23');// '\x23'为16进制转义字符,0x23对应10进制数为35

    return 0;
}

程序输出:

shell
efg
abefg
83
35

字符处理函数

头文件 <ctype.h> 中声明了许多字符处理函数,主要分为两大类:字符分类函数和大小写转换函数。

cpp
// 字符分类函数
int isalnum(int c);     // c是字母数字吗?
int isalpha(int c);     // c是字母吗?
int isblank(int c);     // c是空的吗?即' '或'\t'
int iscntrl(int c);     // c是控制字符吗?
int isdigit(int c);     // c是十进制数吗?
int isgraph(int c);     // c是一个打印字符吗(除了空格)?
int islower(int c);     // c是小写字母吗?
int isprint(int c);     // c是一个打印字符吗(包括空格)?
int ispunct(int c);     // c是标点吗?
int isspace(int c);     // c是空白字符吗?
int isupper(int c);     // c是大写字母吗?
int isxdigit(int c);    // c是十六进制数字吗?

// 大小写转换函数
int tolower(int c);
int toupper(int c);

读/写字符

使用scanf和printf

scanf 和 printf可以使用转换说明符 %c 对单个字符进行读写操作:

cpp
char ch;

scanf("%c", &ch);       // 读取单个字符
printf("%c", ch);       // 输出单个字符

注意: scanf 函数在读字符时,不会跳过前面的空白字符。如果需要跳过前面的空白字符,则要在转换说明符 %c 前面加一个空格:

cpp
scanf(" %c", &ch);      // 跳过空白字符,然后读取ch

scanf格式串中的空格意味着"跳过零个或着多个空白字符"。

使用getchar和putchar

C 语言还提供了另外一些读写单个字符的方法,其中比较常用的是 putchar 函数。

putchar 用于写单个字符:

cpp
int putchar(int c);

其作用是向标准输出 stdout 写入一个字符。如果写入成功,则返回写入的字符,否则 返回 EOF。

getchar 用于读单个字符:

cpp
int getchar(void);

其作用是从标准输入 stdin 读入一个字符,并且把读入的字符返回。如果读到文件的 末尾,或者在读的过程中发生错误,那么返回 EOF。

注意:putchar 和 getchar 函数的执行效率要高于 printf 和 scanf。

getchar函数常用于一些惯用法中。如:

cpp
while (getchar() != '\n'){}     // 跳过其余部分
测试char类型的最⼤值及其数据溢出的情况
数据类型占用空间取值范围
char1字节-128到 127(-2⁷ ~ 2⁷-1)
unsigned char1字节0 到 255(0 ~ 2⁸-1)
c
#include <stdio.h>
#include <stdlib.h>

int main() {
    char ch;
    //符号位溢出会导致数的正负发生改变
    ch = 0x7f + 2;//127+2

    printf("%d\n", ch);
    // 0111 1111
    //+2后 1000 0001,这是负数补码,其原码为 1111 1111,结果为-127
    //最⾼位的溢出会导致最⾼位丢失

    unsigned char ch2;
    ch2 = 0xff + 1;//255+1
    printf("%u\n", ch2);
    // 1111 1111
    //+1后 10000 0000, char只有8位最⾼位的溢出,结果为0000 0000,⼗进制为0

    ch2 = 0xff + 2;//255+1

    printf("%u\n", ch2);
    // 1111 1111
    //+1后 10000 0001, char只有8位最⾼位的溢出,结果为0000 0001,⼗进制为1

    return 0;
}

程序输出:

shell
-127
0
1