单引号
char c;
c = 'a';
c = '1';
c = 'A';
单引号在字符常量时使用,表示单个字符。当在单引号中出现两个及以上字符时或没有字符时,编译出错,且C语言中不允许出现空字符。
在 js 中,下面代码是会打出 false 的,因为 js 语言本质上把字符和数字当成两种不同的基本类型。
function str(){
console.log('a' === 97)
}
在 C语言中,则会打出 true ,因为在C语言中,整数/字符/二进制 都是同样以二进制存储的,处理字符时会先根据 ascll 码来转化为整数进而转化为二进制。
这里就需要字符集的概念给一个变量赋值一个字符时,会先去字符集查找对于的整数去存储,当程序想要表达一个字符时需要拿到根据整数在字符集中对应字符。
‘ \0’ 在字符集中对应的整数就是 0,0 和 ‘ \0’ 在计算机中存储的时候是完全一致的,把一份数据从不同角度观察的结果。
C语言通常将数值常量以及字符常量视为 int 而不是将字符常量视为 char,就会有奇怪的现象 32 位的值赋给 8 位的存储单元。
char a = 'a';
转义字符的三种表达方式:\n,\ + 八进制,\x + 十六进制
双引号
C 语言没有字符串类型但也可以很好地处理字符串,双引号在表示字符串常量时使用,可以表示0到多个字符组成的字符串,允许出现空字符串。
char s1[] = "a";
char s2[] = "a1A";
‘A’ 表示单个字符大写字母A,占用1个字节空间
“A” 表示字符串,该字符串只有1个大写字母A组成,占用2个字节空间,每个字符串末尾自动会加上一个空字符 ‘\0’
ctype.h库
对于判断一个字符是否是某种类型,我们很容易就想到使用遍历的方法,
if('0' <= c && c <= '9')
但是数字的字符是连续的,对于其他的类型比如标点符号需要多个区间判断,这就有点性能过于昂贵了,比如下面判断是否有空格
if(c == ' ' || c == '\t' || c == '\n')
Ascall 表总共有 256 个字符,于是 ctype.h 做法是在内部维护一个转换表,提供我们传入宏的参数作为下标来取到表中的值
#define islower(c) (_Ctype[(int)(c)] & _LO)
由于宏参数没有类型,我们先进行类型转化
static const short ctype_tab[257] = { 0, /* EOF */
_BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
_BB, _CN, _CN, _CN, _CN, _CN, _BB, _BB,
_BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
_BB, _BB, _BB, _BB, _BB, _BB, _BB, _BB,
_SP, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
_PU, _PU, _PU, _PU, _PU, _PU, _PU, _PU,
XDI, XDI, XDI, XDI, XDI, XDI, XDI, XDI,
XDI, XDI, _PU, _PU, _PU, _PU, _PU, _PU,
_PU, XUP, XUP, XUP, XUP, XUP, XUP, _UP,
_UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
_UP, _UP, _UP, _UP, _UP, _UP, _UP, _UP,
_UP, _UP, _UP, _PU, _PU, _PU, _PU, _PU,
_PU, XLO, XLO, XLO, XLO, XLO, XLO, _LO,
_LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
_LO, _LO, _LO, _LO, _LO, _LO, _LO, _LO,
_LO, _LO, _LO, _PU, _PU, _PU, _PU, _BB,
};
const short *_Ctype = &ctype_tab[1];
至于 _LO 就是宏中预先对每种类型设置的唯一的一个数,比如小写字母就是 _LO
当判断 ‘a’ 是否为小写字母的时候,使用宏 islower,通过宏替换,也即执行(_Ctype[(int)(c)] & _LO)
预处理之后,假设当前的 c 是 ‘a’ 那么变成了: (_Ctype[(int)(‘a’)] & _LO) 字符’a’的值为97所以接下来便是: (_Ctype[97] & _LO)
_Ctype[97]的转换宏是 _LO ,通过查_Ctype 转换表,_LO 的值又是 0x10,所以最后是:(_LO & _LO) ——> 0x10 & 0x10 ——> 1, 说明当前字符为小写字母