【C语言进阶(1)】数据存储

news2024/9/20 21:25:30

文章目录

  • Ⅰ 数据类型介绍
    • ⒈类型的基本分类
  • Ⅱ 整形在内存中的存储
    • ⒈原码、反码、补码
    • ⒉大小端介绍及判断大小端
  • Ⅲ 浮点型在内存中的存储
    • ⒈浮点数在内存中的存储规则
    • ⒉IEEE 754 对 M 和 E 的存取规定
    • ⒊解释前面的题目

Ⅰ 数据类型介绍

基本内置类型

类型类型名称
char字符数据类型
short短整型
int整形
long长整形
long long更长的整形
float单精度浮点型
double双精度浮点型

类型的意义

  • 使用这个类型开辟内存空间的大小(大小决定了使用范围)。
  • 如何看待内存空间的视角。

⒈类型的基本分类

1. 整形类型

- char
	- [X] unsigned char
	- [X] signed char
- short
	- [X] unsigned short (int)
	- [X] signed short (int)
- int
	- [X] unsigned int
	- [X] signed int
- long 
	- [X] unsigned long (int)
	- [X] signed long (int)
  • 注:字符在内存中存储的是字符的 ASCII 码值,ASCII 码值是整形,所以字符类型归类到整形类型。

2. 浮点数类型

- float
- double

3. 构造类型(自定义类型)

- 数组类型
- 结构体类型	struct
- 枚举类型	enum
- 联合类型	union

5. 指针类型

- int*	 pi
- char*	 pc
- float* pf
- void*  pv

6. 空类型

  • void 表示空类型(无类型)
  • 通常应用于函数的返回类型、函数的参数、指针类型。
int test1(void);		//test1 函数没有参数
void test2(int a);		//test2 函数没有返回值

Ⅱ 整形在内存中的存储

⒈原码、反码、补码

1. 数据在内存中存储的都是二进制

  • 计算机能够处理的都是二进制的数据。
  • 整形和浮点型数据在内存中都是以二进制的形式进行存储的。
  • 整数在内存中存的都是二进制补码

2. 整形的二进制表示形式

  • 整形的二进制表示形式有 3 中:原码、反码、补码。、
  • 正整数:原码、反码、补码相同。
  • 负整数:原码、反码、补码需要进行计算。

3. 负整数原反补的计算方法

  • 对于负整数来说,(原码 → 补码)或者(补码 → 原码)的方法都是一样的。
  • 统一进行取反加1的操作即可。
    • 例:算出 -10 的反码,再将 -10 的反码转回原码。
//原码 → 补码,可以采用取反加 1 的操作
10000000 00000000 00000000 00001010 //-10 的原码
11111111 11111111 11111111 11110101 //-10 的反码
11111111 11111111 11111111 11110110 //-10 的补码

//补码 → 原码,也可以采用取反加 1 的操作
11111111 11111111 11111111 11110110 //-10 的补码
10000000 00000000 00000000 00001001	//先取反 
10000000 00000000 00000000 00001010 //再加 1。-10 的原码就还原出来了

5. 补码存放整数的特征

  • 当符号为为 0 的时候,后边的 1 越多,整数的值就越大;
  • 当符号位为 1 的时候,后边的 0 越多,整数的值就越小。

6. 整数在内存中存补码的原因

  • 使用补码,可以将符号为数值位统一进行处理。
  • 同时,加法和减法也可以统一处理(CPU 只有加法器),又因为补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
    • 例:分析 CPU 对 1-1 这个操作是如何计算的
- 因为 CPU 只有加法器,所以 1-1 会被转换成 1 + (-1) 来进行计算。
- 如果采用原码的方式进行计算的话,结果就会出大问题了。

00000000 00000000 00000000 00000001 	// 1 的原码
10000000 00000000 00000000 00000001 	//-1 的原码
10000000 00000000 00000000 00000010		//1+(-1),结果居然变成了 -2,显然很有问题

- 所以补码这种东西就这么应运而生了。
00000000 00000000 00000000 00000001		// 1 的补码
11111111 11111111 11111111 11111111		//-1 的补码
10000000 00000000 00000000 000000000	//1+(-1),进位产生第 33 个比特位,最高位的 1 就没用了 

- 将最高位的 1 丢掉之后,补码相加的结果就是 0 了。
00000000 00000000 00000000 00000000

⒉大小端介绍及判断大小端

  • 平时有观察过整型变量在内存中的存储的话就应该发现,整型的值在内存中是倒着存放的。

在这里插入图片描述

1. 大小端的定义

  • 大端字节序存储:把一个数据的低位字节处的数据存放在内存的高地址处,高位字节的内容放在内存的低地址处。
  • 小端字节序存储:把一个数据的高位字节处的数据存放在内存的高地址处,低位字节的内容放在内存的低地址处。

在这里插入图片描述

2. 数据的低位和高位

  • 如 123 有个十百位,从右往左 3 为低位,1为高位。
  • 一个数据也有低位与高位,从右往左分别为低位 → 高位。
  • 如:0x11223344,这样一个 16 进制 4 个字节的数据从右往左按照字节划分高低位。

3. 大小端存在的原因

  • 在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,。但是在C语言中除了1 个字节的 char 之外,还有 2 个字节的 short型,4 个字节的 int 型等等。
  • 由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
int a = 0x11223344;	
//a 所占的 4 个字节每个字节分别存着 11 22 33 44
//这 4 个字节的内容该以什么样的顺序往内存里存,就看当前机器的大小端字节序了。

4. 判断当前机器的大小端字节序

  • 拿出整型数据 1 存在内存中的第一个字节的内容进行判断,如果是 1 则为小端,为 0 则为大端。

在这里插入图片描述

#include <stdio.h>

int check_sys()
{
	//对 pa 解引用访问 a 的第一个字节的内容,
	//返回的结果是 1 则为小端,0 则为大端

	int a = 1;
	char* pa = (char*)&a;
	return *pa;
}

int main()
{
	if (check_sys)
	{
		printf("当前机器为小端字节序\n");
	}
	else
	{
		printf("当前机器为大端字节序\n");
	}

	return 0;
}

在这里插入图片描述

Ⅲ 浮点型在内存中的存储

  • 浮点数在内存中也是以二进制的形式存储的,但存储的方式并不是原码、反码、补码这样。

常见的浮点数

  • 3.1415926
  • 1E10:科学计数法的表示形式,1E10 表示为 1.0 * 1010
  • 浮点数包括:float、double、long double 类型。
  • 浮点数表示的范围:float.h 中定义。

用一个例子引出浮点数的存储规则

在这里插入图片描述

  1. n 是以整型的形式存进去的,① 也是用整型的形式打印的,所以这个 9 倒没什么问题。
  2. 将 n 强转后赋给 pFloat,但是 n 在内存中还是以整数的形式存储的,② 以浮点型的方式取出却是这么个结果,说明整数和浮点数的存储形式是不一样的。
  3. 通过浮点数的视角,往 n 里面放个 9.0 进去,③ 将 n 里存的 9.0 以整型的形式打印,又一次说明整数和浮点数的存储规则不一致。
  4. 以浮点数的形式放 9.0 进去,又以浮点数的形式往外拿,④ 的打印结果是 9.0 也没什么问题。
  • 打印的数据和打印的格式的类型一定要匹配

⒈浮点数在内存中的存储规则

  • 想要明白 num 和 *pFloat 在内存中明明是同一个数,以浮点数和正数的打印结果却相差这么大,就一定要搞懂浮点数在计算机内部的表示方法。

浮点数的表示形式

根据国际标准 IEEE 754,任意一个二进制浮点数 V 可以表示成 (-1)S * M * 2E 的形式。

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

举个栗子

  • 10 进制的 5.5 写成二进制是 101.1,相当于 1.011 * 2 2,然后这个数又是个正数,就可以加上 (-1)0 变成 (-1)0 * 1.011 * 22
  • 那么按照上面浮点数的表示形式可以得出,S = 0,M = 1.011,E = 2。

IEEE 754 规定

  • 对于 32 位的浮点数(float),最高的 1 位存储符号位 S,接着的 8 位存指数 E,剩下的 23 位存储有效数字 M。

在这里插入图片描述

  • 对于64位的浮点数(double),最高的 1 位存着符号位 S,接着的 11 位存着指数 E,剩下的 52 位存着有效数字 M。

在这里插入图片描述

⒉IEEE 754 对 M 和 E 的存取规定

1. 有效数字 M 的存储

  • 之前说过, M 的范围为 [1,2),也就是说过,M 可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。
  • IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxx 部分。
    • 比如保存 1.01 时,只保存 01,等到要读取的时候再把第一位的 1 加上去。
  • 这样做的目的是节省 1 位有效数字。以 32 位浮点数为例,留给 M 只有 23 位,将第一位的 1 舍去以后,等于可以保存 24 位有效数字。

2. 指数 E 的存储

  • 指数 E 位一个无符号整数(unsigned int),这意味着,如果 E 位 8 位,取值范围就是 0 ~ 255。如果 E 为 11 位,取值范围就是 0 ~ 2047。
  • 但是,科学计数法中的 E 是可以出现负数的(如:2-1),所以 IEEE 754 规定,存入内存时 E 的真实值必须再加上一个中间数,然后转成二进制数存进内存中。
  • 对于 8 位的 E,这个中间数是 127,对于 11 位的 E ,这个中间数是 1023。
    • 例如:2-1 的 E 是 -1,在存成 32 位浮点数时,保存成 -1 + 127 = 126,即 0111 1110。在存成 64 位浮点数时,保存成 -1 + 1023 = 1022,即 011 1111 1110。

小试牛刀

  • 分析 float f = 5.5 在内存中的存储
- 十进制:5.5 → 二进制 101.1
- 101.1 写成科学计数法的形式为:(-1)^0 * 1.011 * 2^2
- 其中:s = 0,,E = 2(记得加中间值),M = 1.011(只存小数点后的数)。
- 开始存储:0 10000001 01100000000000000000000	// S 存 0,E 存 2+127 = 129 的二进制,M 存 011 后补 0
  • 验证:4 位转 1 位的十六进制结果应该是 40 b0 00 00。
    • f 也是以小端的形式存储的。

在这里插入图片描述

3. 指数 E 从内存中取出

将指数 E 从内存中取来分为三种情况:

  1. E 不全为 0 或不全为 1:用存进内存中的 E 的值减去中间数(127 或 1023),得到真实值,再将有效数字 M 前加上第一位的 1。
    • 例:0.5 的二进制形式为 0.1,由于规定正数部分必须为 1,所以将小数点右移 1 位,则为 1.0 * 2-1
    • 其阶码为 -1 + 127 = 126,表示为 01111110,而尾数 1.0 去掉整数部分为 0,补齐 0到 23 位 00000000000000000000000,则其二进制表示形式为:
0 01111110 00000000000000000000000
  1. E 全为 0
    • 加了中间数 127 之后往里存结果还是 0,这时浮点数的指数 E 等于 1-127(或者1-1023)即为真实值。
    • 此时有效数字 M 不再加上第一位的 1,而是直接还原成 0.xxxxxx。这样做是为了表示 ± 0,以及接近于 0 的很小的数字。
  2. E 全为 1
    • 8 个位上全是 1 的话,内存中存的就是 255,真实的 E 就是 255 - 127 = 128 了,指数为 128 的话这次直接就无穷大了。
    • 此时,如果有效数字 M 全为 0,表示 ± ∞(具体的正负取决于符号位 S)。

⒊解释前面的题目

在这里插入图片描述

  • 分析 ②:
00000000 00000000 00000000 00001001 //9 的补码
- 站在 pFloat 的角度看 9 的补码,它认为这是个浮点数,那么 pFloat 对 9 的理解就是:
0 00000000 00000000000000000001001 	//S、E、M

- 内存中存的 E 为全 0,的 E 为全 0 特殊情况就出现了。此时:
E 还原成 -126
M 还原成 0. 00000000000000000001001
S 还原成 0

- 真实的数字应该是:(-1)^0 * 0.00000000000000000001001 * 2 ^-126,直接就无穷小了。
- 所以打印结果才会是 0.000000
  • 分析 ③:
- 十进制 9.1001.0 二进制,写成科学计数法:(-1)^0 * 1.001 * 2^3
- S = 0,E = 3,M = 001,开始往里存(E 别忘了加中间数)。
0 10000010 00100000000000000000000 //9.0 的二进制序列

- 以 n 的视角看这段二进制序列 n 任务这是个整数的补码
01000001 00010000 00000000 00000000 
- 最后再以 %d 的形式打印,%d 认为  这是个超大的正整数
- 所以打印结果就是 1,091,567,616

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/835395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玄子Share - Mybatis 项目模板使用指南

玄子Share - Mybatis 项目模板使用指南 项目结构图 mybatis-config.xml 配置模板设置 参数 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.…

pycharm运行pytest无法实时输出信息

需要去掉控制台输出。根据查询相关信息显示pycharm运行pytest无法实时输出信息&#xff0c;需要去掉pycharm里面的运行模式&#xff0c;点击减号&#xff0c;再点击加号&#xff0c;添加python执行文件即可实时输出信息。 问题描述&#xff1a; 使用pycharm运行代码时&#x…

24考研数据结构-树与森林

目录 5.4树、森林5.4.1树的存储结构1. 双亲表示法(顺序存储)&#xff1a;2. 孩子表示法(顺序链式)3. 孩子兄弟表示法&#xff08;链式&#xff09; 5.4.2树、森林与二叉树的转换5.4.3树、森林的遍历1. 树的遍历先根遍历后根遍历层序遍历&#xff08;队列实现&#xff09; 2. 森…

LeetCode-26-删除有序数组中的重复项

一&#xff1a;题目描述&#xff1a; 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯…

AI相机“妙鸭相机”原理分析和手动实现方案

妙鸭相机 一个通过上传大约20张照片&#xff0c;生成专属自拍。在2023年7月末爆火&#xff0c;根据36Kr报道&#xff0c;妙鸭相机系阿里系产品&#xff0c;挂靠在阿里大文娱体系下&#xff0c;并非独立公司。 使用方法是上传20张自拍照片&#xff0c;之后可以选择模板生成自己…

神码ai火车头标题伪原创【php源码】

这篇文章主要介绍了如何把python 代码打包成可执行软件&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图&#xff1a; Python 程序封装-打包成exe程…

以指标驱动,保险、零售、制造企业开启精益敏捷运营的新范式

近日&#xff0c;以“释放数智生产力”为主题的 Kyligence 用户大会在上海前滩香格里拉大酒店成功举行。大会包含上午的主论坛和下午的 4 场平行论坛&#xff0c;并举办了闭门会议、Open Day 等活动。来自金融、零售、制造、医药等行业的客户及合作伙伴带来了超过 23 场主题演讲…

CSS调色网有哪些

本文章转载于湖南五车教育&#xff0c;仅用于学习和讨论&#xff0c;如有侵权请联系 1、https://webgradients.com/ Wbgradients 是一个在线调整渐变色的网站 &#xff0c;可以根据你想要的调整效果&#xff0c;同时支持复制 CSS 代码&#xff0c;可以更好的与开发对接。 Wbg…

selenium 截屏

当前环境&#xff1a; Windows 10 Python 3.7 selenium 3.141.0 Google Chrome 115.0.5790.110 &#xff08;64 位&#xff09; from selenium import webdriver import base64if __name__ __main__:#driver webdriver.Chrome()driver.get(https://www.baidu.com/)# 1.…

服务端高并发分布式结构演进之路

目录 一、常见概念 1.1基本概念 二、架构演进 2.1单机架构 2.2应用数据分离架构 2.3应用服务集群架构 2.4读写分离 / 主从分离架构 2.5引入缓存 —— 冷热分离架构 2.6垂直分库 2.7业务拆分 —— 微服务 一、常见概念 1.1基本概念 应用&#xff08;Application&am…

powerdesigner各种字体设置;preview字体设置;sql字体设置

1.设置左侧菜单&#xff1a; 步骤如下&#xff1a; tools —> general options —> fonts —> defalut UI font ,选择字体样式及大小即可&#xff0c;同下图。 2.设置preview字体大小&#xff08;sql预览&#xff09; 步骤如下&#xff1a; tools —> general o…

问道管理:两市股指冲高回落,沪指一度突破3300点,券商、保险板块领涨

8月4日&#xff0c;两市股指高开高走&#xff0c;沪指一度突破3300点。开盘后&#xff0c;沪指、深成指涨近1%&#xff0c;创业板指、上证50指数涨幅超1%。职业方面&#xff0c;券商、稳妥板块领涨&#xff0c;传媒、石油、半导体、银行、煤炭等板块均上扬&#xff0c;互联金融…

Oracle锁的学习

Oracle数据库中的锁机制 数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时&#xff0c;在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据&#xff0c;破坏数据库的一致性。 在数据库中有两种基本的锁类…

拓展商业视野:利用企业变更记录 API 剖析企业策略与决策

引言 随着商业竞争日益激烈&#xff0c;企业的战略与决策成为成功与否的关键因素。在这样的背景下&#xff0c;利用变更记录查询API成为了企业洞察竞争对手、揭示市场动态、发现商业机会的重要工具。本文将深入探讨变更记录查询API的应用&#xff0c;揭示它如何拓展商业视野&a…

【项目 进程14】2.30 守护进程(1) 2.31 守护进程(2)

文章目录 2.30 守护进程&#xff08;1&#xff09;终端进程组会话进程组、会话、控制终端之间的关系进程组、会话操作函数守护进程2.31 守护进程&#xff08;2&#xff09;守护进程的创建步骤写一个守护进程&#xff0c;每隔2s获取一下系统时间&#xff0c;将这个时间写入到磁盘…

【枚举+trie+dfs】CF514 C

Problem - 514C - Codeforces 题意&#xff1a; 思路&#xff1a; 其实是trie上dfs的板题 先把字符串插入到字典树中 对于每次询问&#xff0c;都去字典树上dfs 注意到字符集只有3&#xff0c;因此如果发现有不同的字符&#xff0c;去枚举新的字符 Code&#xff1a; #in…

会用这个医疗小技巧,升职加薪不加班!

在医药领域&#xff0c;温湿度监控是确保药品质量和安全性的重要环节。药品的生产、存储、运输和展示过程中&#xff0c;温湿度变化可能对药品的有效性产生不良影响&#xff0c;因此需要实时监测和管理环境条件。 通过有效的温湿度监控系统&#xff0c;医药企业和医疗机构能够确…

docker系列--解决hyper-v导致docker无法启动问题

一、问题 windows docker desktop 启动报错异常&#xff0c;导致docker无法启动成功 我们看到问题出在hyper-v的问题上&#xff0c;搜索解决方法&#xff0c;官网常见问题如下 Overview | Docker Documentation 二、解决 Hyper-V 已安装并正常工作 在BIOS中启用虚拟化 Wind…

mapstruct 错误 java.lang.NoSuchMethodError: Ljava/lang/Double 错误

问题描述 在使用 mapstruct 的过程中遇到错误 java.lang.NoSuchMethodError: Ljava/lang/Double 错误 问题解决 maven clean, 然后 maven install Build -> Rebuild Project 执行 maven install 时, 如果报错 找不到 xxx 类, 但 ctrl鼠标左键 发现可以点进去这个类, 那…

[openCV]基于赛道追踪的智能车巡线方案V1

import cv2 as cv import os import numpy as npimport time# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表""&quo…