在了解数据的是如何存储之前,我们需要先知道C语言有哪些数据类型
希望你能看到最后,相信你一定会有收获
内置类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
内置类型分为两大类
整形
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
浮点型
float
double
long double
构造类型
数组类型
结构体类型struct
枚举类型enum
联合类型union
指针类型
内置类型指针
构造类型指针
空类型
void
,空类型不能用来定义变量,通常用来表示函数参数个返回值类型
类型的意义
1.决定了编译器给该类型变量分配的存储空间有多大
2.决定了看待该类型变量中数据的视角
整形在内存中的存储均是以
补码
的形式存在,关于补码
的相关概念点我
整形-1在内存中存放的二进制就应该是
11111111111111111111111111111111
内存中的数据以16进制显示,转换成2进制的确是32个1
对于字节数大于1的类型,必然存在着数据在该类型中
存放顺序
的问题,
数据的存放顺序称为存储模式
数据的存储模式有大端字节序存储
和小端字节序
存储两种模式
存储模式和硬件有关,与编译器无关
想要知道是
大端字节序
还是小端字节序
,我们只需要取一个大于1字节数据类型的数据的低地址
位置的数据,观察这个数据是该数字的高位还是低位
int Check_System()
{
int a = 1; //0x00000001
char* p = (char*)&a; //只需要取出一个字节的内容,定义char*
return *p; //*p等于1说明低地址的字节为a的地位,为小端存储
}
int main()
{
int ret = Check_System();
if (ret == 1)
{
printf("小端存储\n");
}
else printf("大端存储\n");
}
每一个整形都有它能表示的最值,当该类型的变量所存储的数据超过了能表示的最值MAX,MIN,存储的数据会转变成另外一个数据,而这个数据一定在该整形所能表示的范围中,这叫做
整形溢出
知道了当
存储的数据超过了该变量类型所能表达的最值
后,我们不得不思考,每个类型的最值怎么求?
首先可以参考头文件
#include //整形类型所能表示的最大小值
#include //浮点型类型所能表示的精度及其范围
其次,知道这些范围是怎么来的可以帮助我们更好的理解数据的存储
signed char
举例
signed char
的补码
从8个0到8个1一共有2^8
次方中情况,我们为了将每一种二进制序列表示成一个数,就将10000000规定为MIN
我们知道10000001
是-127
的补码,所以我们也可以通过拿-127的补码减一
得到-128
的补码10000000
1.
#include
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; }
2.
#include
int main()
{
char a = -128;
printf("%u\n",a);
return 0; }
3.
#include
int main()
{
char a = 128;
printf("%u\n",a);
return 0; }
//4.
#include
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
//按照补码的形式进行运算,最后格式化成为有符号整数
}
5.
unsigned int i;
for(i = 9; i >= 0; i--) {
printf("%u\n",i);
}
6.
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0; }
7.
#include
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
用2进制
表示就是01000000101000000000000000000000
这和5的补码
不一样
因此引出一个概念,浮点数的存储规则是什么?
根据IEEE(电气电子工程师学会)754标准,一个任意的二进制浮点数V可以表示成下面这种形式
规定32位的浮点数最高位是符号位S,接着的8位是阶码E,最后的23位是尾数M
规定64位的浮点数最高位是符号位S,接着的11位是阶码E,最后的52位是尾数M
对于存储浮点数特别规定:
1.因为有效数字m为1.xxxx,所以规定存储时的尾数M是有效数字去掉1后的二进制序列
2.因为指数位e可能为负数,所以规定存储时的阶码E是指数位e-偏移量,对于32位浮点数来说,偏移量是127,对于64位浮点数来说偏移量是1023
对于取出浮点数时特别规定:
1.阶码全为0或1
因为存储浮点数时将有效数字的1去掉了,所以正常情况
下取出浮点数的有效数字时需要将去掉的1补回来,取出浮点数的指数位时需要将内存存储的阶码减去偏移量
前面所说的正常情况
是值E不为全0或全1
2.阶码E为全0
取出来时阶码E还原成真实指数值e需要在阶码的基础上减去偏移量,如果阶码E全为0,那么指数值为1-127或者1-1023,规定有效数字m不在加上第一位的1,而还原成0.xxxxx
这样做是为了更好的表示±0以及接近于0很小的数字
3.阶码E全为1
阶码全为1,真实指数值就是阶码的值加上偏移量,最后的还原出来的小数就是±无穷大
注:若float型的小数的二进制中指数小于-127,及加上偏移量后阶码仍然为0,这样的小数精度超过了float型的精度,需要用double存储来表示
浮点数
5.0f
的二进制是101.0
1*2^0+0*2^1+1*2^2+0^2(-1)
5.0f就可以写成(-1)0 x 1.01 x 22
根据IEEE754规则
5.0f的二进制序列就是
0
1000001
01000000000000000000000
1.int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
2.int main()
{
float a = 7.5f;
printf("%d\n", a);
int b = 2;
printf("%f\n", 2);
return 0;
}
特别注意:当char、short、不足int数据进行压栈时,会自动转换为4个字节,float进行压栈时自动转换为double类型,这就是为什么%d可以打印char、short类型的数据而不会影响到后面的参数。看起来%hd和%c是读取两字节和一字节的数,但事实上%hd是在4字节中读取两字节,舍去4字节剩下的部分接着往下读。同理,%c则是在4字节中读取一字节,舍去往下读。这才是为什么short型和char型既可以用%d读,也可以用%hd和%c读的原因。
3.int main()
{
long long a = 0x0000004400000033;
printf("%c %c\n", a);
return 0;
}
4.int main()
{
float a = 7.5f;
printf("%lld\n", a);
return 0;
}
最近开学了,没什么时间用来整理博客了,真的是百忙之中抽时间来写博客 ,后面更新的速度可能会慢点,也有可能开始更行高数、线性代数,毕竟确实是整理在博客上面才会记忆犹新啊,看到最后,希望能动动小指头三连