0x00 前排吹水
刚刚发现,原来微信公众号的推文还可以用markdown写。激动得我赶紧装个13冷静一下(逃。不过话说回来,说到char这个东西,可能也是让很多新手朋友难(dan)受(ten)不已的东西。那么char和一般的变量类型又有什么区别呢?今天来一起聊聊。By the way, 0x表示16进制,再问......先看看下面的例子吧
ch是一个char类型的变量,并且赋初值'a':
为什么cout输出ch+1 会输出98?
为什么同一个变量按照%d(整形输出)的结果是97?按照字符型%c输出又变成了'a'呢?
0x01 char究竟是个什么东西?
其实,char和int,float,double这些一样。如我们指针那篇说的一样,它是一种变量类型。那么,这种类型定义的变量,存的是什么呢?字符!就这么简单.....那么,什么是字符?低头看看你的键盘,上面显示的都是字符。比如a, b, c, A, B, C, *, ^, +,.....包括上面的逗号和点都是字符。And, 包括一些不可见的,比如\n回车符, \t制表符等等。char类型的变量就是存这些玩意儿的。
0x02 char和数字有什么关系?
在此之前,让小编问大家一个问题。我们都知道,变量存的值都是放在内存中的。既然char类型变量存的是字符,那么当我char ch = 'a'的时候,ch在内存中对应的东西是不是真的是一个字符'a'?
我只能说:
傻子都知道,计算机底层只认识0和1,说白了,在内存中除了0和1,再无其他...... 不信?我们写个程序到内存看看呗,在此之前让我打开宇宙中最强的IDE, Visual Studio 2015。貌似还没有之一(linux程序员就要过来打我了,逃 )
两句cout<<内存地址 实在坑爹,给我来了一堆烫烫烫 f.....k.... 所以用了printf("p")表示输出内存地址。不过看到using namespace突然想起某乎上一个大神说的一句话:
敢于把using namespace写在头文件的人,都是敢于改变世界的人.......
貌似扯远了,回到正题,程序写好。砸门在printf后面下个breakpoint。然后在内存窗口中看看变量ch对应的内存中存的到底是什么玩意儿吧。
睁大你们的眼睛,仔细瞧瞧。字符a呢???没有。里面存的是97,数字97,数字97。所以啊,char类型的变量,并不是你们想象中的那样,把一个个字符硬生生塞进内存中放着。说了,计算机底层只认识0and1,再也容不下任何的小三......所以,在内存中它只能存数字啊,数字啊,数字啊,字啊,啊.....
0x03 ASCII码表
这个表可不是泥萌去年买的那种表可以比的。~~前面说了,既然内存中只能存一堆01,那我的字符怎么办。哎,人的智慧总是无穷的。我们将一个个数字和我们需要的字符对应起来。比如我们要字符a对应的数字是97.那么我要存字符a的时候,是不是在内存中存一个97就能代表字符a了呢?ASCII码表就这样产生了。给大家找了张简单的让大家感受一下:
所以啊,每个字符我们都用一一对应的数字对应了起来。这样要存字符的时候,我们就把字符相应的数字给塞进内存就行了。关于编码的相关知识,这里也有一段很长的历史,包括中国的GB2312,GBK,以及现在国际通用的uncode,and 还有什么utf-8.....估计讲到明天都扯不完。感兴趣的读者自行上网查一下吧。
0x04 相关疑惑的解释
我们再来明确一个问题,那上面说的,字符在内存中是数字的形式存的。那数字也是以数字的形式存的。当我访问这块内存的时候,我怎么知道里面放的97是对应字符a,还是实实在在的数字97?这里大家就明白类型的重要性了吧。比如下面代码
#include <iostream> using namespace std; int main() { char ch = 97; int num = 97; cout<<ch<<num<<endl; return 0; }
输出结果: a 97 为什么?变量ch和num在内存中存的都是数字97.这点毫无疑问,但是cout看到ch的时候,发现。卧槽这是一个char类型的变量,那我不能直接输出97,我要到ASCII码表里面找找,哦....97对应的是字符a,好吧我就把a给输出来吧。然后cout遇到num,这是一个int类型的变量啊,里面存的是97?哦,那把97输出来吧。
所以,取决于类型啊少年们......
回到一开始的疑问,
- 为什么cout 输出ch+1是98?
我们上面说了,char类型定义的变量,其存的字符,都在ASCII码表里面有一一对应的值。我们只是把值存进去了,ch本身在内存中放的是97(字符a在ASCII码表中对应97),这个没问题。ch+1,内存中相应的值变成了98.然后cout输出ch+1的时候,不应该是b吗?(b在ASCII中对应的数字是98).我们上面说了,cout输出什么,是不是还要看类型?那么ch+1类型是什么?char类型?卧槽回家种田去吧.....说了多少遍,当char类型和int类型运算的时候,编译器会进行隐式的转换,把char类型变成int类型再进行运算,最终运算的结果自然也是int整形了。当cout遇到整形,那tm还管三七二十一,直接输出98了。
- 为什么同一个变量按照%d(整形输出)的结果是97?按照字符型%c输出又变成了'a'呢? 我们之前讲过,printf输出的时候,不管里面存的是什么,只会老老实实按照我们给的格式输出。ch再内存中存的是97,那么按照整数%d输出,他就是输出97.按照字符型%c输出,他就老老实实到ASCII码表里面找对应的字符呗~~~
0x05 写在后面
好了今晚就聊这么多。第一次用markdown写推文,还是特么的有点紧张的。咳咳~其实很多东西,从本质上的理解更为重要,特别程序这块。比如最近看的8086汇编,感触最深的就是,在计算机底层,万物即bin(二进制)。各式各样的指令和数据也是变成一堆0和1放在内存中等着CPU去执行......扯远了,突然发现还有两篇英语课文没看......f....k...希望考试周的小伙伴们都能把GPA考得高高的。
最后送大家一句比较伤感的话:
有时候真的决定某些事情,就像char * 一样,从一开始就注定,无法改变。