字符溢出分析(数据类型范围以及‘\0’重新认识)

来源:互联网 发布:哪里买域名 编辑:程序博客网 时间:2024/06/05 10:57
#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){    char a[1000];    int i;    for (i=0;i<1000;i++)    {         a[i] = -1-i;    }    cout<<strlen(a)<<endl;    system("pause");    return 0;}

做题目的时候没有考虑到字符溢出,自然做错了
【分析】
我们知道计算机底层只认识0,1,所以任何数据到了底层都会通过计算转换成0,1,那么负数是怎样存储呢?由于“-”无法存入内存,我们把它做个标记,把基本数据类型的最高位腾出来,用来存符号,同时约定如下:如果最高位是1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号。

bool型为布尔型,占1个字节,取值01。BOOL型为int型,一般认为占4个字节,取值TRUE/FALSE/ERROR。sbyte型为有符号8位整数,占1个字节,取值范围在128~127之间。bytet型为无符号16位整数,占2个字节,取值范围在0~255之间。short型为有符号16位整数,占2个字节,取值范围在-32,768~32,767之间。ushort型为无符号16位整数,占2个字节,取值范围在0~65,535之间。int型为有符号32位整数,占4个字节,取值范围在-2,147,483,648~2,147,483,647之间。uint型为无符号32位整数,占4个字节,取值范围在0~4,294,967,295之间。long型为64位有符号整数,占8个字节,取值范围在9,223,372,036,854,775,808~9,223,372,036,854,775,807之间。ulong型为64位无符号整数,占8个字节,取值范围在0~18,446,744,073,709,551,615之间。float型为32位单精度实数,占4个字节,取值范围3.4E+10的负38次方~3.4E+1038次方之间。double型为64位实数,占8个字节,取值范围1.7E+10的负308次方~1.7E+10的正308次方。

for循环内,当i的值为0时,a[0]的值为-1.在计算机系统中,数值一律用补码来表示。在用两个补码的数相加时,如果最高位(符号位)有进位,则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数+1.
-1的补码为0xff,-2的补码为0xfe……
当i的值为127时,a[127]的值为-128,而-128是char类型数据能表示的最小的负数。
当i继续增加,a[128]的值肯定不能使-129,因为这时候发生了溢出。-129需要9位(1 1000 0001)才能存储下来,而char只有8位,所以最高位被丢弃,剩下的8位是原来9位补码(1 111 1111)的低8位的值,即0x7f。当i继续增加到255时,-256的补码低8位全为0,然后当i增加到256时,-257的补码的低8位全为1,即低8位的补码为0xff,如此又开始一轮新的循环……
按照上面的分析,a[0]~a[254]里面的值都不为0,而a[255]的值我0.
‘\0’ 的ASCII值为0。
strlen函数是计算字符串长度的,并不包含字符串最后的’\0’。判断一个字符串是否结束的标志就是看是否遇到’\0’;如果遇到’\0’,则认为字符串结束。
由此分析,strlen(a)的值为255。

0 0
原创粉丝点击