在看C语言相关书籍时候,遇到一道题,想了好久原因才豁然开朗,记录下来方便以后观看,代码如下:
int main(void)
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1 - 1;
}
printf("%d\n",strlen(a));
return 0;
}
刚开始乍一看以为是1000,然后觉得不太对,再猜测是255,答案就是255,但是却没有明白其中缘由,然后看了书本的解释,第一遍好像懂了,第二遍又不会了,第三遍心中闪过某种念头,第四遍第五遍…本人愚笨,最终看了9遍才有豁然开朗的感觉。
首先明白问题是求打印的值是多少,然后看strlen(a),很明显是计算出字符串的长度。那对于一个数组来说,它的字符串长度要怎么算呢?strlen()这个函数是遇到“\0”就结束,所以目的就是:要在数组a当中从a[0]开始,一直碰到"\0"才结束计数。
接下来分析代码,重要部分是在循环里,a[0]是-1,a[1]是-2。那a[1000]是多少呢?-1000吗?很明显不是这么随意。
这里要明白一点,那就是char类型,在缺省的情况下,char是signed类型的,除非程序员声明为unsigned类型。如果是unsigned的话,它的范围就是0-255。而signed类型是-128-127。
那么以a[0] = -1,a[1] = -2这样的方式推导下去,a[127] = -128。此时已经到达了char类型的最小范围,那a[128]是多少?我在这里的时候,有了分歧,想法1是-129,想法2是127,想法3是0。
到这一步,就需要明白,数值在计算机内是以补码的形式存在的,在这道题目下,-1的补码为0xff,-2的补码为0xfe…而-128的补码为1000 0000,-129的补码是1 0111 1111。char类型数据只有8位,所以要舍弃低8位之外的数据,即变为0111 1111,是7f,也就是127,即a[128] = 127。在DEVC++中做了测试,果然如此
那么a[128]=127,接着推下去:a[129] = 126…又直到a[254]的时候,值为1,到a[255]时,值就变成了0。所以到此结束。a[0]-a[254]的值不为0,一共有255个数,那么遇到a[255]时候,strlen停止计数,并且不将0计算在内。
我最后反思了一下自己为什么需要看那么多遍,那就是没有很好的将strlen遇到0时候停止弄明白,我刻板的以为一定是遇到"\0",而数组的某个元素的值为0时候,没有将它反应成"\0"。在用DEVC++时候,我通过查看变量时候才意识过来。但是我在看书的时候,a[128]时候,作者写的是7f,而我没有很快反应过来7f就是127。并且作者写到i继续增加到255时候,值为-256那么补码低8为全为0,即0x00,而i增加到256时候,-257的补码是0xff,它跟-1的补码一样,所以进行了新的一轮循环。
用DEVC++时候,能够直接看到数组元素值变化过程,所以 理解比较快,而书本作者的讲解,讲的层度更深一些,难明白(根本原因是我一直没意识到"\0"),但是知识能收获更多。