C语言的数据存储

前言

主要讲解了:

  1. 压栈的基本思想
  2. 大小端的存储
  3. 整型 和 浮点型在内存中不同的存储方式

原码 反码 补码

计算机的存储和计算都是用的二级制补码
正数的原码,反码,补码都相同

原码

是数值的二级制形式 例: 10 的二级制为 1010
负数的最高位二级制位为1(表示符号位)

反码

符号位不变,其他位取反(1变成0,0变成1)

补码

在反码的基础上 加上 1
例如 反码为 1010 则补码就是 反码加1 为 1011

从补码转换为真值

  1. 可以用相反的计算求出真值,补码减一然后再取反
  2. 可以再进行一次"取反加1"(再进行一次变补码的计算),这样依旧可以变成原来的值,计算机也是采用的这个方式

函数调用的参数压栈

是一种数据结构
每一个函数调用都会在内存的栈区上开辟一块空间!
先进的后出,后进的先出(存储从底部开始)
在这里插入图片描述

在这里插入图片描述

大小端存储(字节存储顺序)

大端存储

把数据的低位字节序内容存放在高地址处
高位字节序的内容存放在低地址处

小端存储

VS2022采用的就是小端存储
把数据的低位字节序内容存放在低地址处
高位字节序的内容存放这高地址处
在这里插入图片描述

判断当前程序是大端存储还是小端存储

 #include<stdio.h>
void main()
{
	int a = 1;
	char* p = (char*)&a;
	if (*p == 1) printf("小端\n");
	else printf("大端\n");
}

数组存储时,应用的大小端

	int arr[] = { 1,2,3,4,5 };
	short* p = (short*)arr;
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		*(p + i) = 0;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d", arr[i]);
	}

在这里插入图片描述

整型在内存中存储

整型有int,short,char,long以及相关的有符号无符号等

有符号char范围为 -128~127 (8位二进制256种可能)
当赋值超出范围时,负数+256正数-256
例: char i=-129; i中其实放的是-129+256=127

无符号char范围为 0~255 (8位二进制256中可能)
例1

 #include<stdio.h>
void main()
{
	char a = -128;
	printf("%u\n", a);
}

打印为一个超级大的整数
char类型只能存放一个字节(8比特位),前面的二进制位舍去
先求出-128的补码,然后只取后八位,1000 0000
打印时整型提升前面全部补符号位,111……1000 0000
%u为无符号整型,正数三码都相同,直接打印出111……1000 0000的十进制数

例2

	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}

i=0通过后,i还会自减,i==-1
二级制补码为1111………1111
创建i的时候为无符号整型,直接识别-1为正数,正数三码相同
i==超大的正整数 每次i减到-1都会变成这个数,因此造成死循环
例3

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

char范围为-128~127 当赋值超出范围时,负数+256正数-256
循环数为:-1 -2 -3 -4 -5…… -128 127 126 125…… 0 -1 -2 -3……
strlen()函数是算出字符实际长度,即\0之前的字符有多少个
找到0就是\0(ASCII码) 0前面一共有128(-1到-128 )+127(1到127 )=255个

浮点型在内存中存储

根据国际标准IEEE(电气和电子工程协会)754
任意一个二进制浮点数V可以表示成下面的关系:(-1)s * M * 2E
在这里插入图片描述在这里插入图片描述在这里插入图片描述

存储方式

s :直接在二进制首位放上0或1
M :M的小数点前总是1,所以不记录,只记录小数点后的数,数写前面后面全部补零 如 M1.001 在二进制中是 0010000000000……
E :E为无符号整数,但是E可能为负 如 0.5(十进制) -> 0.1(二进制) -> 1.0*2-1
所以要加上一个中间数,E为8位时,中间数是127 如 -1+127=126转换为二级制存入内容
E为11位时,中间数是1023 如 -1+1023=1022转换成二级制存入内存

浮点数 5.5
(-1)0 * 1.011 * 22
s=0 M=1.011 E=2
s=0 M=011 E=2+127=129
0 10000001 01100000……
(内存中是小端存储,40 b0 00 00 -> 00 00 b0 40)

二级制转回十进制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsQak6HN-1691319736854)(…/素材/进阶_1_3.png)]
E为全零时 规定此时E等于1-127(或者1-1023)
有效数字M不再加上第一位的1,而是还原为0.XXXXXX的小数
这要做视为了表示正负0(无穷小),因为后面小数点限制(保留多少位)会显示出0.000000
E为全1时 表示正负无穷大

printf()中类型如果与参数不符,则可能打印出不是想要的结果

在这里插入图片描述

扩展

栈区

栈区与栈不同,局部变量存放在栈区中,如果访问数组跟下面例子一样超出了,则可能造成死循环,i的地址与数组最后一个元素的地址挨在一起,超出到i的地址再赋值就会一直这样循环
VS中存储固定相隔8个字节(在int类型中是两个元素)

c和c++的内存存储

在这里插入图片描述

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS(程序)回收。分配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
    主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值