字符类型
字符型变量用于存储一个单一字符,在 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 类型的变量可以存储单个字符,注意:字符字面值应该用单引号括起来。
char ch;
ch = 'a';
ch = 'A';
ch = '0';
ch = ' ';
字符操作
,毕竟字符和整数之间的关联是非常强的。当计算中出现字符时,C 语言会使用字符对应的整数值,如:
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'
我们也可以像比较整数那样对字符进行比较。比如,下面的代码可以把小写字母变成大写字母。
/* not commended, toupper function is better */
if (ch >= 'a' && ch <= 'z')
ch = ch - 'a' + 'A';
我们还可以像下面这样使用 for 循环遍历所有的大写字母:
for (ch = 'A'; ch <= 'Z'; ch++) ...
把字符当作整数来处理,可以给我们带来方便,但也可以导致我们写出一些无意义的表达式:
'a' * 'b' / 'c'; /* Don't do this */
字符变量定义与输出示例
#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;
}
程序输出:
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 | 数字0 | 000 |
\ddd | 8进制转义字符,d范围0~7 | 3位8进制 |
\xhh | 16进制转义字符,h范围09,af,A~F | 3位16进制 |
注意:红⾊字体标注的为不可打印字符。
字符转义序列使用起来是很方便的,但是它有一个问题:字符转义序列没有包含所有 的不可打印的 ASCII 字符,而且它也不能表示 ASCII 以外的字符。
数字转义序列可以解决上面的问题,它可以表示任意一个字符。我们可以使用八进制 或者十六进制来书写数字转义序列。
- 八进制转义序列由
\
和一个最多 3 位的八进制数字组成。比如 ESC 的编码为 27, 用八进制表示就是 33,因此它可以表示成\33
或者\033
。注意,和八进制整数不 一样的是,转义字符中的八进制数不需要以 0 开头。 - 十六进制转义序列由 \x 和一个十六进制数组成。比如 ESC 字符也可以写成
\x1b
或\x1B
的形式。其中 x 必须小写,但是十六进制数字不限大小写。
当转义序列作为字符常量使用时,必须用一对单引号括起来。比如:`\n', '\33' 或 '\x1B'。
编写代码测试
#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;
}
程序输出:
efg
abefg
83
35
字符处理函数
头文件 <ctype.h> 中声明了许多字符处理函数,主要分为两大类:字符分类函数和大小写转换函数。
// 字符分类函数
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 对单个字符进行读写操作:
char ch;
scanf("%c", &ch); // 读取单个字符
printf("%c", ch); // 输出单个字符
注意: scanf 函数在读字符时,不会跳过前面的空白字符。如果需要跳过前面的空白字符,则要在转换说明符 %c 前面加一个空格:
scanf(" %c", &ch); // 跳过空白字符,然后读取ch
scanf格式串中的空格意味着"跳过零个或着多个空白字符"。
使用getchar和putchar
C 语言还提供了另外一些读写单个字符的方法,其中比较常用的是 putchar 函数。
putchar 用于写单个字符:
int putchar(int c);
其作用是向标准输出 stdout 写入一个字符。如果写入成功,则返回写入的字符,否则 返回 EOF。
getchar 用于读单个字符:
int getchar(void);
其作用是从标准输入 stdin 读入一个字符,并且把读入的字符返回。如果读到文件的 末尾,或者在读的过程中发生错误,那么返回 EOF。
注意:putchar 和 getchar 函数的执行效率要高于 printf 和 scanf。
getchar函数常用于一些惯用法中。如:
while (getchar() != '\n'){} // 跳过其余部分
测试char类型的最⼤值及其数据溢出的情况
数据类型 | 占用空间 | 取值范围 |
---|---|---|
char | 1字节 | -128到 127(-2⁷ ~ 2⁷-1) |
unsigned char | 1字节 | 0 到 255(0 ~ 2⁸-1) |
#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;
}
程序输出:
-127
0
1