数据的在内存中的存储

数据的在内存中的存储

1.类型的基本归类

1.整形

1660025985098

char分为三种,因为不同编译器,在不准确制定char的类型的时候,可能处理成singed,有时候就是unsigned
1660007531086

其他的整形都默认是 signed

1660007550734

2.构造类型:(自定义类型)

a:数组类型
b:结构体类型
c:枚举类型
d:联合类型

3.指针类型

4空类型(void)
a:指针空类型 void*p 任何一种都可以放,但是没有办法正常使用,一般是暂时存放某个地址
b:函数返回类型

2.整形在数据中的存储

2.1原码,补码,反码

计算机的整数有这三种二进制表示方法,即原码,补码和反码
三种表示方法均有符号位和数值位两部分,符号位是最高位,用1表示负

正数的原,反,补相同
原码到补码有一种方式>>原码取反>>加一得到补码
补码到原码两种方式>>
a:补码-1,取反的得到原码
b:补码取反,+1得到原码

对与整形来说,数据存放在内存中存放的是补码,原因是
1660027290043

其中减法怎么理解呢,比如3-5其实是3+(-5)
1660028350419

2.2大小端介绍

先来看这样一个问题
1660029173677

看到这里我们可能就有疑惑了,-10的16进制不应该是
ff ff ff f6么,为什么是倒着存放呢,而且f6为什么没倒过来呢

这里呢是以字节为单位存储的,每两个16进制数字是8个比特位,也就是1个字节,而为什么会出现倒着存放的情况就涉及到了:大端和小端存储

定义(什么是大端小端)
1660029578287

为什么会出现大端和小端
对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
1660029908020

看起来还是难以理解,让我们画图来看一下
1660030356000

通过画图我们就能简易理解什么是大端存储什么是小端存储了

如果一个数据超过一个字节,就会有以下两种存储模式

1660010139818

来看一道面试题
1660030557898

1660030902239

就比如1这个情况,如果是小端存储那么我的第一个字节存放的数据就是1,大端存储就是0,那我们只需要判断第一个字节是什么就好了,代码实现如下

int check()
{
  int a=1;
  if(*(char*)&a==1)/*先强制转换类型,找到a的第一个字节数据*/
     return 1;
  else 
     return 0;
}
int main()
{
   if(check()==1)
      printf("小端");
   else
      printf("大端");
   return 0; 
}

2.3练习

2.3.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;
}

这里会输出什么呢 -1 -1 1 ?
正确答案是 -1 -1 255
为什么会相差这么大呢
1660032134530

再补充一个整形提升,上面的11111111当然不可能就这样打印出来因为是%d,所以会发生整形提升,而整形提升的规则如下
a:负数的整形提升,高位补1,比如char = -1; 11111111
补充之后就是11111111111111111111111111111111
注意这都是补码,输出的时候要转换成原码
b:正数整形提升,高位补0, 比如char d= -1;11111111
补充之后就是00000000000000000000000011111111

2.3.2整形数据类型大小范围的由来

我们都知道数据类型的取值范围,可你知道他们是怎么来的么

先以 signed char类型为例

1660034168806

同理那signed int也是如此
1660034539358

那unsigned 类型就更好说了,就是从1到最大值(没有符号位)

1660034801815

2.3.3练习整形提升和截断

那来看一个题

#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}//输出结果是什么呢

答案是4294967168 为什么呢
1660035494052

再来一个

#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);//千万不能认为就是128
return 0;
}

答案还是4294967168,这次又是为什么呢
1660036066589

再来一个

1660061354904

3.浮点型在内存中的存储

3.1引入

先来看这样的一个标准

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式

a: (-1)^S * M * 2^E
b: (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
c: M表示有效数字,大于等于1,小于2。
d: 2^E表示指数位

3.2转换为科学计数法

怎么理解呢,下面直接来看一个例子
1660109350624

3.3存放

那怎么以二进制的形式存放在内存中呢(以flaot类型为例)
1660109742154

好既然有这样一个图,那刚才的5.5怎么存放的呢
1.S位置正常放,是几就是几
2.在存放E的时候先加上127再存放(double就加1023)因为E是一个无符号整数
3.存放M的时候,把整数部分忽略掉(取的时候再把1补上),只存放小数部分

我们再以5.5为例看看具体是怎么存放的
1660111321643

double类型也是一样的
1660111558379

3.4取出

取出的时候E的情况比较复杂分为以下三种
a:E不全为0或不全为1 这时候直接减去127即可(double就减去1023)
b:E全为0 M还原的时候不再补充1 为什么呢 E全为零那它在加上127之前说明就是-127,一个数的指数是-127说明是一个很小的数了,一定是小于0.0…所以不用在补充1,再乘以2-126(double就是21022)
c:E全为1 这时候M全为0, 说明这个数是无穷大的 , 正负取决于符号位

3.5练习

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;
}

结果会输出什么呢

答案是
1660112713386

1660113386238

1660113930605

3.6补充

在上述的例子中我们用到了很特殊的5.5,不难发现0.5可以用2^-1很容易表示出来,但是比如像5.3这样的浮点数,我们是无法精确表示的,小数点后位数越多越精确,这也就解释了为什么浮点数类型不能直接比较大小的原因

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值