数据在内存中的存储

1.整型

空类型:

void表示空类型

void无法定义变量,因为类型不明确,就无法定义变量,开辟空间大小。但可以做函数的返回值,前提是该函数的返回类型为空。

void *

void *可以定义变量,能赋值,说明void *本身给变量开辟了空间,但void *对应的变量不能被直接解引用。
void * 有什么用呢?
void *有非常特殊的应用,就是void *可以用来接收任意类型,常用于接受任意指针。

整型在内存中的存储:

  1. 整型在计算机中存储的是补码。

无符号数:原码=反码=补码
有符号数:最高位代表符号位,正(0),负(1)
有符号正数:原码=反码=补码
有符号负数:进行原反补转换
原码:对应数的绝对值的二进制序列,特殊:有符号数,其中最高位要设置为符号位
反码:符号位不变,其它位按位取反
补码:反码+1(符号位要参与运算,即使通常很少影响到符号位)

2.数据写入的过程

原反补约束的是原始数据
先给变量开辟空间
将数据转换位对应的二进制序列,但转化的过程和目标变量无关
数据写入到对应的开辟好的空间中
完成
写入数据:本质是现将数据转化成对应的二进制序列(与目标变量无关),然后写入对应的内存空间里

  1. 数据读取的过程

读一个变量的时候,先看它的数据类型,决定了我们如何看待该变量内部的二进制序列的含义
不管我们如何看待二进制序列,二进制序列本身不会发生改变,但是经过类型的解释,二进制代表的含义就会发生改变
读入数据:本质是根据变量的类型,来解释内存里面的二进制是什么含义

  1. 变量的类型起的作用

开辟空间的大小
读取数据的时候,如何解释二进制序列

  1. 大小端存储模式

大端模式:数据的低位存储在高地址中,数据的高位存在低地址中
小端模式:数据的低位存储在低地址中,数据的高位存在高地址中

数据按照字节为单位存储在计算机中,可以被划分为若干部分,每一部分对应的“权值”是不同的,只要有不同就会有高低。
内存访问的基本单位是字节,只要是字节,就会有地址,只要有地址,就会有大小。
在数据读取时,同样也要考虑大小端问题。

如何知道当前计算机是否为大端存储还是小端存储?
可以写一个代码实现

int main()
{
	int i = 1;
	char *p =(char *)&i;
	printf("%d\n", *p);
	return 0;
}

如果是大端,输出0,如果是小端输出1。
 
 
 
几个毕竟有意思的题:

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d\n", strlen(a));
	return 0;
}

strlen函数,遇到‘\0’就停下来,本质上就是0,计算长度的时候,不会包含0。
char类型的取值范围为[-128,127]。
a[i]的由-1依次减小,直到-128,下一个值为127。
即a[128]=-129
但是char类型被解释为127

//1000 0001   129
//1 0111 1111  -129

但char类型只有一个字节大小,会发生截断问题,则为

//0111 1111  127

在这里插入图片描述
利用这个图片来理解这个题,逆时针走,直到0,然后再继续走,但求strlen时,在0处就会停下,故中间经历了255个元素,故该题的答案最后为255。

unsigned char i = 0;

int main()
{
	for (i = 0; i <= 255; i++)
	{
		printf("bit!");
	}
	return 0;
}

变量i的数据类型为unsigned char 故i的取值范围为[0,255],所以main函数里的循环条件会一直满足,导致死循环。
 

 
总结:看一个变量时,必须先看该变量的数据类型,因为数据类型决定了我们如何看待变量,以及变量的取值范围和大小(即如何解释这个变量)。

 

 
2.浮点型

浮点型的存储和整型的区别比较大,先看一个例子。

int main()
{
	int n = 9;
	float *p = (float *)&n;
	printf("%d\n", n);
	printf("%f\n", *p);
	*p = 9.0;
	printf("%d\n", n);
	printf("%f\n", *p);
	return 0;
}

输出结果是什么呢?
在这里插入图片描述
为什么差距有这么大呢?
先看看浮点型数据在内存中如何存储:

根据IEEE754标准,任意一个二进制浮点数可以表示为下面的形式:
(-1)^S * M * 2^E
(-1)^S表示符号位,当s=0时,为正数,s=1时,为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位
比如说9.0,写成二进制为1001.0,相当于1.001 * 2^3。按照上面的格式,则S=0,M=1.001,E=3

单精度浮点数存储模型为:
在这里插入图片描述
IEEE754标准规定,M大于等于1,小于2,M可以写成1.xxxxxxx,但在计算机保存M的时候,只保存后面的xxxxxx,最后读取的时候再将第一位的1加上去。这样做的目的是可以节省1位有效数字,虽然M只有23位,但可以保存24位有效数字。

比如说1.01,保存的时候就为01。
指数E的介绍:

  1. E为一个无符号整数(unsigned int),如果E为8位,则取值范围为[0,255],E为11位(双精度浮点数),取值范围为[0,2047]。在科学计数法中,是存在负数的,所以IEEE754规定,在存入内存时E的真实值必须再加上一个中间数,对于8位的E,中间数为127,对于11位的E,中间数为1023。比如2^10的E是10,所以保存32位浮点数时,保存为10+127=137.即10001001.
  2. E不全为0或不全为1时,直接用指数E的计算值减去127,得到真实值,再将有效数字M前加上第一位的1。例如9.0

0 1000 0010 0010 0000 0000 0000 0000 000
写代码验证一下:

int main()
{
	float n = 9;
	int *a = (int*)&n;
	int i = 31;
	for (; i >= 0; i--)
	{
		printf("%d ", ((*a) >> i) & 1);
	}
	printf("\n");
	return 0;
}

在这里插入图片描述
符合预期结果。

  1. E全为0,此时,浮点数的指数E等于1-127(1-1023),即为真实值,有效数字不再加上第一位的1,而是还原为0.xxxxx的小数,,这是为了表示±0,以及接近0的很小的数字。
  2. E全为1,如果有效数字M全为0,则表示±无穷大。
    像上面的9.0,如果直接给整型 n,其二进制会被解释为一个特别大的数。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值