数据在内存中的存储
数据类型介绍
char //字符 short //短整形 int //整形 long //长整形 long long //更长的整形 float //单精度浮点数 double //双精度浮点数
类型的意义
-
使用这个类型开辟的空间的大小(大小决定了使用范围)。
-
如何看待内存空间。
类型的基本分类
char: //符在内存中存储的是ASCII码值,ASCII码值是整形,所以字符类型属于整形家族。 signed char unsigned char short signed short unsigned short int signed int unsigned int long signed long unsigned long float double > 数组类型 > 结构体类型 struct > 枚举类型 enum > 联合类型 union int *pi; char *pc; float* pf; void* pv; 空类型: void 表示空类型(无类型) 通常应用于函数的返回类型、函数的参数、指针类型
整形在内存中的存储
变量的创建是在内存中开辟空间。空间的大小是根据不同的类型决定的。
比如
int a = 20; int b = -10;
我们知道a分配四个空间。那如何存储呢。先了解一下概念
原码、反码、补码
计算机中有三种二进制表示方法分别为原码反码补码,三种表示方法由符号位和数值位组成。符号位用0表示正。用1表示负。符号位为0的原反补相同。为1时的三种表示方法各不相同。
-
负数的原码:直接按照数值翻译成二进制。符号位为1即可获得原码。
-
反码:符号位不变。其他位依次按位取反得到反码。
-
补码:由反码+1得到。
对于整形来说:数据存放在内存中其实存放的是补码
大小端介绍
什么是大端小端: 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中; 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。
百度2015年系统工程师笔试题: 请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
int test(){ int a = 1; return (*(char*)&a); } int main() { int a = 20; int b = -10; if (test()) { printf("小端"); } else { printf("大端"); } return 0; }
将a的地址强制转换成char指针类型。因为char指针一次只能访问一字节数据。&a取出的是a的起始地址。如果结果为1。那么在内存中的就是01000000。否则就是00000001。
练习
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; }
首先将-1赋给a。 -1的原码为10000000 00000000 00000000 00000001,反码11111111 11111111 11111111 11111110, 补码为11111111 11111111 11111111 11111111。 但是char类型的a只能存放一字节。所以a存放的是-1补码的低八位11111111。b和c同理。存放的也是八个1,有符号数和无符号数在存储的时候是一样的。只有在使用的时候才会有所区别。 然后进行输出。要输出的类型为%d也就是十进制有符号数。要将abc进行整形提升,a与b同为signed char有符号。提升时高位补符号位 最后为11111111 11111111 11111111 11111111。因为输出的是有符号数。所以要将提升后的补码转换为原码也就是10000000 00000000 00000000 00000001。也就是-1。c为无符号类型。整形提升时高位补0,最后为00000000 00000000 00000000 11111111。符号位为0代表正数,正数原反补相同。所以c输出255;
#include <stdio.h> int main() { char a = -128; printf("%u\n",a); return 0; }
-128的原码是10000000 00000000 00000000 10000000,反码为11111111 11111111 11111111 01111111,补码为11111111 11111111 11111111 10000000。a只有一字节。所以存储的是10000000。%u为十进制无符号整形。需要的a进行整形提升。a为有符号数补符号位 最后为11111111 11111111 11111111 10000000。由于输出的为无符号数,所以不用转换直接输出11111111 11111111 11111111 10000000的十进制表达4294967168
int main() { char a = 128; printf("%u\n",a); return 0; }
128的原反补相同00000000 00000000 00000000 10000000,存入a的为10000000同上。所以输出和上面一样。由此我们可以看出。不要看赋值的是多少。而是他真正存储的是多少。
int i= -20; unsigned int j = 10; printf("%d\n", i+j); //按照补码的形式进行运算,最后格式化成为有符号整数
-20的原码为10000000 00000000 00000000 00010100 反码为11111111 11111111 11111111 11101011 补码为 11111111 11111111 11111111 11101100。10的原反补相同,00000000 00000000 00000000 00001010;
11111111 11111111 11111111 11101100 00000000 00000000 00000000 00001010 =11111111 11111111 11111111 11110110(i+j)输出为有符号十进制 需要将补码转换为原码 。结果为-10;
int main(){ unsigned int i; for(i = 9; i >= 0; i--) { printf("%u\n",i); } return 0; }
输出9-0,然后输出随机数(可通过计算得出)。当i==0的时候,执行i--。i=0-1也就是i=0的补码加上-1的补码。-1的补码是11111111 11111111 11111111 11111111。此时i存储的是11111111 11111111 11111111 11111111,i是无符号数。在使用时直接就用了,所以是个很大的数。
int main() { char a[1000]; int i; for(i=0; i<1000; i++) { a[i] = -1-i; } printf("%d",strlen(a)); return 0; }
a[0]=-1 a[1]=-2 从-1到-128,然后127-1一共225个数,所以答案为255。
-128的原码为10000000 00000000 00000000 10000000反码为11111111 11111111 11111111 01111111补码为11111111 11111111 11111111 10000000。-1的补码为11111111 11111111 11111111 11111111
11111111 11111111 11111111 11111111 11111111 11111111 11111111 10000000 答案为1 11111111 11111111 11111111 01111111 01111111 放入a[i]也就是127
unsigned char i = 0; int main() { for(i = 0;i<=255;i++) { printf("hello world\n"); } return 0; }
i=255时i++,i=255的补码加1的补码
00000000 00000000 00000001 00000000 00000000 00000000 00000000 00000001=00000000 00000000 00000001 00000001。char为一字节取低八位00000001也就是1所以此程序无限输出