小引
我们前面学习了数据在内存中的存储,包括整型,浮点数等等数据类型。
这里我们简单举几个例子,通过这些典例的讲解,希望可以对内存有一个更客观、更深刻的理解。
典例 1:
#include <stdio.h>
int main()
{
char a= -1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
- %d为有符号的十进制的整数,虽然
a
变量是一个字符类型,但是是按照十进制格式打印,所以依然输出-1。 signed char
当前来看和char
是等效的,所以前两个输出结果是一样的。- 无符号的
char
型变量c
按照有符号的int
型格式打印,相当于强制类型转换。十六进制0xff
,理解为有符号就是-1
,理解为无符号就是255
。
数据在内存中具有一定的存储形式,但是存储同样的内容,可以按照不同的方式来理解。
所以输出:-1 -1 255
典例 2:
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
char
类型变量a
打印为无符号整型大致过程就是:
char
类型先整型提升为int
类型,-128
的二进制之前补了很多符号位1
,再变成无符号类型,结果变成了一个很大的正数。
char
类型表示的范围是-128 ~ 127
,-128
的表示最低一个字节1000 0000
,前面的字节都是用符号位1
补充的。用无符号的方式打印,结果就变成了一个很大的数,接近了一个整数能表示的最大范围了。
所以输出:4294967168
典例 3:
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
char
类型最大表示到127
,127
为0111 1111
,加上一变成了1000 0000
,所以将128
赋予char
没有足够的空间存储,超过表示范围,越界行为。128
的二进制表示为1000 0000
,和-128
相同,所以对于char
类型变量,正负在内存中的表示方式一样,所以打印出来和上题相同。
如果两个数据在内存中存储的形式是相同的,再按照相同的方式来理解,结果也肯定是相同的。
所以输出:4294967168
典例 4:
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
//按照补码的形式进行运算,最后格式化成为有符号整数
- 两个变量相加,但是类型不同,所以发生了隐式类型转换,
unsigned
类型要比int
类型精度高,所以二者都是无符号类型,用无符号表示以补码形式存储的负数,所以二者的和应该是一个很大的数。 -20
为ff ff ff ec
10
为00 00 00 0a
二者按照二进制相加为ff ff ff f6
,理解为有符号为-10
。
打印方式是有符号的int
类型,所以这个类型转换没有实际必要,一切以打印方式为主。
所以输出:-10
典例 5:
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
- 无符号类型的变量是恒
> 0
的,所以循环条件i >= 0
就恒成立,无法跳出循环,出现死循环,这是一个很经典的错误。 - 变量
i
已经是0
时,再对它进行--
,相当于+= -1
。
00 00 00 00
+ff ff ff ff
= 理解为有符号为-1,无符号为42亿9千万
,所以两个无符号相减,如果被减数小于减数就会变成负数,理解为无符号就是一个很大的数。
所以结果是:死循环
典例 6:
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%lu",strlen(a));
return 0;
}
a[]
不可以视为字符串,因为没有初始化不知道\0
在哪里会出现。strlen
返回的是长度,不存在负数,所以使用无符号长整型来打印。如果要对变量a
进行strlen
,就说明a
要是一个字符串,而a[]
字符数组不是字符串。- 内层循环的结果:
-1 :<ff ff ff ff
>
-2 :<ff ff ff fe
>
-3 :<ff ff ff fd
>
… …
当结果是-256
:<ff ff ff 00
>时
char
类型只保留一个字节,此时a[i]
的值为0,也就是ASCII码表上0号的\0
,这个就是字符数组中那个结尾标志,它和之前的字符形成了一个字符串,此时i
的值为255
,不会出现循环1000次及未定义行为的情况。
当下标是255时出现\0
,说明 0 ~ 254是有效位数,总共255
个字符。
所以结果是:255
典例 7:
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello wolrd\n");
}
return 0;
}
- 看似是
0 ~ 255
一共循环256
次,但是unsigned char
类型最多表示的范围是255
,无法跳出循环,所以循环判断条件是恒成立的 255
表示为0xff
,如果此时在给它+1
,变成2
字节的01 00
。因为char
是一个字符,所以截断了高位,变成了0
,又从起点开始循环了。
所以结果是:死循环