使用printf的%s方式打印int数组遇到的问题
使用printf的%s方式打印int数组遇到的问题
几乎所有的C语言程序手册中都钦定了char数组作为字符串的存储方式;
然而所谓的字符不过只是一些ASCII码而已,也就是说他们只不过是一些数字,
于是同样可以用int类型存储单个字符,这完全没问题,用%c去打印一个存储了码值的int变量,也可以打印出对应的字符;
字符串呢?也不过只是将字符的数字串成了一串数组,这样打印的时候把一串数字翻译成对应的字符,然后连着打印出来,就达到了看起来像是字符串的效果;
按照这样的说法,那么一个由char数组组成的字符串和一个由int数组组成的“字符串”,在字符串方面应该表现出相同的性状;
于是为了方便后续处理数据,将字符串存进int数组中,看起来应该也没有问题;
其实本来也没有问题,但是有时候就会有问题,比如:
通过printf("%s")
的方式打印字符串;
这个问题很难遇上,因为少有用int来存字符串这么鬼畜的想法,即使这么干了,也很少会有人想用%s
来把它打印出来,而在这很少遇到的情况中即使遇上了这个问题也很难注意到,因为特征很不明显,而且调一调很有可能被其他更改糊弄过去,最后也不会发现有这样的问题;
很不巧我几次遇到了这个问题,最后总结了一下规律:
现象是用%s
来打印以int数组形式存储的字符串的代码,通过gcc编译之后,一般只会打印一个首字母,或者core dumped
;
现象确定了,原因呢?
既然char数组一直都很正常,我做了一个假设,那就是printf
宏处理%s
的方式是假定它只能是一个char数组,
然后呢?
如果我遇到将只以char数组形式存储的字符串打印出来的需求该怎么处理呢?
因为char类型的特性,它的长度是确定的,1个字节,那么不难想到处理方法是每次读一个字节;
作出推测了,实验验证一下
既然是随便找几个字符串出来做实验,不妨用“baka” “hentai” “urusai”这几个字符串来玩,不过只需要两个字符串,所以就用前两个吧;
char数组存储baka,int数组存储hentai,用printf("%s", ...)
的方式打印;
不出所料打印了baka,和一个h就没了下文;
下来才是重头戏,
先调用sizeof运算符,得到本机为每个int分配的空间大小为4字节长,也就是说一个int的空间能放进4个char
h的ascii码是104,不过现在要用的是二进制码,应该是 0110,1000
以此类推得到e、n、t、a、i的二进制码,
然后每四位组合在一起,剩余的用0补齐,
得到了
01101000011001010110111001110100
01100001011010010000000000000000
两个非常长的二进制数字
由于开头均为0,按照补码规则这两个数字都是正数,然后计算一下他们的数值大小,用十进制可以分别表示为
1751477876
1634271232
(当然也可以用十六进制表示而且更方便,不过表示形式不重要,知道他是这么一个大小就可以了)
将这hentai[0]
和hentai[1]
赋值为这两个数字
其实这一步我是非常忐忑不安的,因为我知道关于机器具体如何处理字节级别的数据还得涉及到大端序和小端序的问题,
不过想这些也没用,先看看能输出什么;
果然输出了个tneh
就没有下文了,
不过特征很明显,这是hentai
前四个字母hent
的倒序输出,而没有下文显然是把后面那个int里面末一个字节的0000,0000
作为NULL
来处理了,程序认为字符串应该在此处结束
于是根据这个规律调整一下二进制的计算方法
得到新的二进制数字为
01110100011011100110010101101000
00000000000000000110100101100001
这两个数字的大小用十进制可以分别表示为
1953391976
26977
再次赋值
于是打印出的结果为hentai
,基本符合实验预测;
同时还知道了这台机器中int的存储方式是倒序的,也就是说一个int之中的4个字节实际上是倒着排列的;
大概就这样吧;
实验代码就丢进实验代码仓库了
终端被ctrl+z的进程怎么回到前台
用nano的时候想要按ctrl+x不小心按到了ctrl+z,于是进程挂在了后台,
用ps
可以看到后台挂了一个editor进程
但是打editor是调不出这个在后台的进程的
方法是直接打fg
把后台程序调入前台
当有多个后台任务的时候
jobs
得到任务号
fg 任务号
调出后台
bg 任务号
调入后台
Knighthana
2021年2月20日