C语言进阶第一课 -----------深度剖析数据在内存中的存储

作者前言

🎂        ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂

   🎂      作者介绍:                              🎂🎂

       🎂 🎉🎉🎉🎉🎉🎉🎉              🎂

          🎂作者id:老秦包你会,         🎂

简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂

             喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨         🎂🎂🎂🎂🎂🎂🎂🎂

                 🎂个人主页::小小页面🎂

                  🎂gitee页面:秦大大🎂

                   🎂🎂🎂🎂🎂🎂🎂🎂
        🎂  一个爱分享的小博主 欢迎小可爱们前来借鉴🎂

_______________________________________________________

______________________________________________________________________

目录

  • 数据类型详细介绍
  • 整形在内存中的存储:原码、反码、补码
  • 大小端字节序介绍及判断
  •  浮点型在内存中的存储解析

——————————————————————————————————————

数据类型介绍

前面我已经介绍了C语言中 常用的数据类型

char         // 字符数据类型
short       // 短整型
int         // 整形
long         // 长整型
long long   // 更长的整形
float       // 单精度浮点数
double       // 双精度浮点数
这些数据类型在内存中开辟的大小也在前面介绍过了,可以利用sizeof进行测试

类型的基本归类

整形家族:
char
unsigned char
signed char
short
unsigned short [ int ]
signed short [ int ]
int
unsigned int
signed int
long
unsigned long [ int ]
signed long [ int ]
注意一下,字符在内存存储的是ASCII值,ASCII值是整形,所以char归类为整形类型
我们平时写的
int a;
signed int a;
unsigned  int a;
int a  == signed int a
https://blog.csdn.net/m0_69984273/article/details/131998273  这里简单的介绍过了char,signed char  和unsigned char  C语言没有规定,取决于编译器 
浮点数家族:
float
double 

 构造类型(自定义):

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

 指针类型

int * pi ;
char * pc ;
float* pf ;
void* pv ;
空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型

 如:int main(void)

整形在内存中的存储

int a = 20;

int b = 10;

 会各自在内存开辟四个字节的空间进行存储

其实计算机能够处理的数据是二进制的,整形和浮点型数据在内存也都是以二进制的形式进行存储。

整数的二进制表示形式有3种:原码、反码、补码

正数的原码、反码、补码相同,

负数的反码是符号位不变,其他位取反, 补码是在反码的基础上加1

#include<stdio.h>
int main()
{
	int a = -10;
	//10000000 00000000 00000000 00001010   原码
	//11111111 11111111 11111111 11110101  反码
	//1111 1111 1111 1111 1111 1111 1111 0110  补码 
	// f    f    f    f    f    f    f    6
	//0xfffffff6

	unsigned int b = -10;// 全部位都是有效位,
	//11111111 11111111 11111111 11110110  补码 

	return 0;
}

4个二进制位表示一个十六进制位 

对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统
一处理;
同时,加法和减法也可以统一处理( CPU 只有加法器 )此外,补码与原码相互转换,其运算过程
是相同的,不需要额外的硬件电路。
假设我们利用原码进行加减   如1 +(-1)
00000000 00000000 00000000 00000001
10000000 00000000 00000000 00000001
这里就会无法确定符号位是否相加
如果使用补码相加
00000000 00000000 00000000 00000001
111111111 111111111 111111111 111111111
不管符号位是否相加都不影响结果

大小端介绍(字节大于等于2的数据)

 在内存窗口中就会发现存储的是补码。但是我们发现顺序有点不对劲

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址
中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位 , ,保存在内存的高地
址中。
例如存储0x11223344

 四个比特位 表示一个十六进制位, 两个十六进制位表示一个字节

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元
都对应着一个字节,一个字节为 8 bit
练习1
设计一个小程序来判断当前机器的字节序
#include <stdio.h>
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0;
}
#include <math.h>
int my_end(int a)
{
	int i = 0;
	int sum = 0;
	for (i = 0; i < 8; i++)
	{
		//计算a补码最右端的8位二进制之和
		int b = (a >> i) & 1;
		sum = sum + b * pow(2, i);
	}
	return sum;
}
int main()
{
	int a = 0;
	scanf("%d", &a);
	char* p = (char*)&a;
	//返回*p开始地址指向的那个字节的大小
	int num = my_end(a);
	if (*p = num)
	{
		printf("小端存储");
	}
	else
	{
		printf("大端存储");
	}
	return 0;
}

练习2

#include<stdio.h>
int main()
{
	char a = -1;
	//10000000 00000000 00000000 00000001  原码
	//11111111 11111111 11111111 11111110 反码
	//11111111 11111111 11111111 11111111
	//因为a为字符变量,只能存储一个字节,存储后8位
	//a-- 11111111
	
	signed char b = -1;
	//b -- 11111111
	unsigned char c = -1;
	//c -- 11111111
	printf("%d %d %d", a, b, c);
	//%d是十进制的形式,打印有符号位的整数
	//因为abc三个未够4个字节,发生整形提升
	//a和b 11111111 11111111 11111111 11111111
	//c    00000000 00000000 00000000 11111111
	return 0;
}

注意一下:%d是十进制的形式打印有符号位的整数

#include<stdio.h>
int main()
{
	unsigned char a = -128;
	//10000000 00000000 00000000 10000000
	//11111111 11111111 11111111 01111111
	//11111111 11111111 11111111 10000000
	//a > 10000000
	// 整形提升
	// 11111111 11111111 11111111 10000000  有符号的
	//	00000000 00000000 00000000 10000000  无符号的
	printf("%d\n", a);
	printf("%u", a);


	return 0;
}

赋值后,先整形提升,把整形提升后的值存储进去,对于无符号数,原码、反码、补码是相同的

 char 的范围为-128~127

unsigned char 为0~255

#include<stdio.h>
int main()
{
	int i = -20;
	//10000000 00000000 00000000 00010100
	//11111111 11111111 11111111 11101011
	//11111111 11111111 11111111 11101100
	unsigned int j = 10;
	//00000000 00000000 00000000 00001010
	printf("%d", j + i);
	//11111111 11111111 11111111 11110110
	//因为%d为有符号十进制输出
	// 在%d看来都是有符号的 转换为原码》10000000 00000000 00000000 00001010




	return 0;
}
#include<stdio.h>
#include<windows.h>
int main()
{
	unsigned int i = 0;
	for (i = 9; i >= 0; i--)
	{
		//无符号的整数都大于等于0的
		printf("%u\n", i);
		Sleep(1000);
	}
	return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		arr[i] = -1 - i;
	}
	printf("%d", strlen(arr));

	return 0;
}

这道题主要体现出char的范围为-128~127 ,不会超过127

浮点型在内存中的存储

常见的浮点数:
3.14159
1E10
浮点数家族包括: float double long double 类型。
浮点数表示的范围: float.h 中定义

 一这张图为例,可以看出整数的存储形式和浮点数的存储形式是不一样的

浮点数存储规则

根据国际标准 IEEE (电气和电子工程协会) 754 ,任意一个二进制浮点数 V 可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^S 表示符号位,当 S=0 V 为正数;当 S=1 V 为负数。
M 表示有效数字,大于等于 1 ,小于 2
2^E 表示指数位。
十进制的:5.5

 二进制:101.1

利用科学计数法,因为是2进制向左移动两位写成  1.011 * 2^2   ,又因为是正数,所以再乘上(-1)^0

最终写成 (-1)^0 * 1.011* 2^2  即S=0 M=1.011  E=2

所以计算机只要存储S M E就行了

 

 

IEEE 754 对有效数字 M 和指数 E ,还有一些特别规定。
前面说过, 1≤M<2 ,也就是说, M 可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。
IEEE 754 规定,在计算机内部保存 M 时,默认这个数的第一位总是 1 ,因此可以被舍去,只保存后面的
xxxxxx 部分。比如保存 1.01 的时
候,只保存 01 ,等到读取的时候,再把第一位的 1 加上去。这样做的目的,是节省 1 位有效数字。以 32
浮点数为例,留给 M 只有 23 位,
将第一位的 1 舍去以后,等于可以保存 24 位有效数字。
至于指数 E ,情况就比较复杂。
首先, E 为一个无符号整数( unsigned int
这意味着,如果 E 8 位,它的取值范围为 0~255 ;如果 E 11 位,它的取值范围为 0~2047 。但是,我们
知道,科学计数法中的 E 是可以出
现负数的,所以 IEEE 754 规定,存入内存时 E 的真实值必须再加上一个中间数,对于 8 位的 E ,这个中间数
127 ;对于 11 位的 E ,这个中间
数是 1023 。比如, 2^10 E 10 ,所以保存成 32 位浮点数时,必须保存成 10+127=137 ,即
10001001。 
include<stdio.h>
int main()
{
	float a = 5.5;
	//101.0
	//(-1)^0 * 1.011 * 2^2
	// S = 0, M = 1.011, E= 2
	// 因为E要加上127后存入即 E= 129
	//0100 0000 1011 0000 0000 0000 0000 0000
	//4      0	  b    0   0    0    0    0  

	return 0;
}

      

指数E从内存中取出还可以再分成三种情况

E 不全为 0 或不全为 1
这时,浮点数就采用下面的规则表示,即指数 E 的计算值减去 127 (或 1023 ),得到真实值,再将
有效数字 M 前加上第一位的 1
比如:
0.5 1/2 )的二进制形式为 0.1 ,由于规定正数部分必须为 1 ,即将小数点右移 1 位,则为
1.0*2^(-1) ,其阶码为 -1+127=126 ,表示为
01111110 ,而尾数 1.0 去掉整数部分为 0 ,补齐 0 23 00000000000000000000000 ,则其二进
制表示形式为 :
0 01111110 00000000000000000000000
E 全为 0
这时,浮点数的指数 E 等于 1-127 (或者 1-1023 )即为真实值,
有效数字 M 不再加上第一位的 1 ,而是还原为 0.xxxxxx 的小数。这样做是为了表示 ±0 ,以及接近于
0 的很小的数字。
E 全为 1
这时,如果有效数字 M 全为 0 ,表示 ± 无穷大(正负取决于符号位 s );
好了,关于浮点数的表示规则,就说到这里。
int main()
{
	int n = 9;
	//0000 0000 0000 0000 0000 0000 0000 1001
	float* pfloat = (float*)&n;
	printf("%d\n", n);
	//0 00000000 00000000000000000001001
	// S = 0 E = 1-127 = -126 M = 0.00000000000000000001001
	//(-1)^S * M * 2^E 
	printf("%f\n", *pfloat);

	*pfloat = 9.0;
	// 1001.0
	//(-1)^0 * 1.0010 * 2^3
	// E = 3+127
	//0 10000010 00100000000000000000000 
	printf("%d\n", n);
	printf("%f\n", *pfloat);
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

组合总和 II——力扣40

文章目录 题目描述法一 回溯 题目描述 法一 回溯 class Solution{ public:vector<pair<int, int>>freq;vector<vector<int>> res;vector<int> seq;void dfs(int pos, int rest){//如果目标值为0&#xff0c;说明可能有一个组合或者rest本身为0 …

基于Java+SpringBoot+Vue的就业信息管理系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

redis 集群 1:李代桃僵 —— Sentinel

目前我们讲的 Redis 还只是主从方案&#xff0c;最终一致性。读者们可思考过&#xff0c;如果主节点凌晨 3 点突发宕机怎么办&#xff1f;就坐等运维从床上爬起来&#xff0c;然后手工进行从主切换&#xff0c;再通知所有的程序把地址统统改一遍重新上线么&#xff1f;毫无疑问…

C语言第十三课--------初阶指针的认识--------重要部分

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; &#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382;…

Hadoop 之 Hive 4.0.0-alpha-2 搭建(八)

Hadoop 之 Hive 搭建与使用 一.Hive 简介二.Hive 搭建1.下载2.安装1.解压并配置 HIVE2.修改 hive-site.xml3.修改 hadoop 的 core-site.xml4.启动 三.Hive 测试1.基础测试2.建库建表3.Java 连接测试1.Pom依赖2.Yarm 配置文件3.启动类4.配置类5.测试类 一.Hive 简介 Hive 是基于…

Nginx的搭建与核心配置

一、Nginx 1、Nginx概述 一款高新能、轻量级Web服务软件系统资源消耗低对HTTP并发连接的处理能力高单台物理服务器可支持30 000&#xff5e;50 000个并发请求。 2、Nginx主要功能&#xff1a; 静态文件服务&#xff1a;nginx可直接提供静态文件服务&#xff0c;HTML、CSS、J…

STM32CubeMX+VSCODE+EIDE+RT-THREAD 工程创建

Eide环境搭建暂且不表&#xff0c;后续补充。主要记录下Vscode环境下 创建Rt-thread工程的过程。分别介绍STM32CubeMX添加rtt支持包的方式和手动添加rtt kernel方式。STM32CubeMX生成工程的时候有"坑"&#xff0c;防止下次忘记&#xff0c;方便渡一下有缘人&#xff…

maven发布到中央仓库

创建账号 https://issues.sonatype.org 【第二步】登录申请新项目 右上角点击Create&#xff0c;Project选择第一项&#xff0c;有的时候带不出来第二个New Project&#xff0c;可以再选一次Project的选项。

centos7 ‘xxx‘ is not in the sudoers file...

如题 执行命令输入密码后时报错&#xff1a; [sudo] password for admin &#xff08;我的账户&#xff09;原因&#xff0c;当前用户还没有加入到root的配置文件中。 解决 vim打开配置文件&#xff0c;如下&#xff1a; #切换到root用户 su #编辑配置文件 vim /etc/sudoe…

2023软件测试面试热点300问(接口自动化测试篇)

分享100道涉及到的接口自动化测试面试题&#xff0c;供大家参考&#xff1a; 我已经把这些面试题全部整理在一个文档里面了&#xff0c;同时还有这些面试题的视频教程分享&#xff0c;全部放在文末了&#xff0c;需要的可以直接去观看&#xff0c;或者直接点击文末小卡片免费领…

路由器DHCP实验

拓扑图 配置 # 配置ip地址并开启dhcp [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip addr 192.168.1.1 255.255.255.0 [Huawei-GigabitEthernet0/0/0]dhcp enable## 配置dns地址 [Huawei-GigabitEthernet0/0/0]dhcp dns-list 192.168.1.5## 指定某个接口开通DHCP 功能…

Zebec Payroll :计划推出 WageLink On-Demand Pay,进军薪酬发放领域

“Zebec Protocol 生态旨以 Web3 的方式建立全新的公平秩序&#xff0c;基于其流支付体系构建的薪酬支付板块&#xff0c;就是解决问题的一把利刃” Zebec Protocol 在创立之初就有着一个十分宏大的愿景&#xff0c;其希望通过 Web3 的方式来进一步打破世界上一些不公平现象。 …

【小沐学NLP】在线AI绘画网站(百度:文心一格)

文章目录 1、简介2、文心一格2.1 功能简介2.2 操作步骤2.3 使用费用2.4 若干示例2.4.1 女孩2.4.2 昙花2.4.3 山水画2.4.4 夜晚2.4.5 古诗2.4.6 二次元2.4.7 帅哥 结语 1、简介 当下&#xff0c;越来越多AI领域前沿技术争相落地&#xff0c;逐步释放出极大的产业价值&#xff0…

OpenCV之信用卡识别实战

文章目录 代码视频讲解模板匹配文件主程序(ocr_template_match.py)myutils.py 代码 链接: https://pan.baidu.com/s/1KjdiqkyYGfHk97wwgF-j3g?pwdhhkf 提取码: hhkf 视频讲解 模板匹配文件 主程序(ocr_template_match.py) # 导入工具包 from imutils import contours # 从…

【LeetCode】236.二叉树的最近公共祖先

题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它…

刷了3个月的华为OD算法题,总结了270多道,谈谈自己的感悟

目录 一、考研二战&#xff0c;入职华为&#xff0c;反向调剂电子科大深圳二、题目描述三、输入描述四、输出描述五、解题思路六、Java算法源码七、效果展示1、输入2、输出3、说明 大家好&#xff0c;我是哪吒。 最近一直在刷华为OD机试的算法题&#xff0c;坚持一天三道题的节…

STL空间配置器入门

STL简介   STL&#xff08;Standard Template Library&#xff0c;标准模板库&#xff09;&#xff0c;从根本上说&#xff0c;STL是一些“容器”的集合&#xff0c;这些“容器”有list,vector,set,map等&#xff0c;STL也是算法和其他一些组件的集合。 谈及组件&#xff0c…

如何在免费版 pycharm 中使用 github copilot (chatGPT)?

起因 在 vscode 中使用了 github copilot 以后&#xff0c;感觉这个人工智能还不错。 但 vscode 对于 python 项目调试并不是特别方便&#xff0c;所以想在 Pycharm 中也能使用同一个 github 账号&#xff0c;用上 copilot 的功能。 不需要等待&#xff0c;安装即用&#xff…

C++和Lua交互总结

C和Lua交互总结 Chapter1. C和Lua交互总结一、Lua与C的交互机制——Lua堆栈二、堆栈的操作三、C 调用 Lua1&#xff09;C获取Lua值2&#xff09;C调用Lua函数示例&#xff1a; 四、Lua 调用 C包装C函数 最后总结一下 Chapter1. C和Lua交互总结 原文链接&#xff1a;https://bl…

数据结构: 线性表(带头双向循环链表实现)

之前一章学习了单链表的相关操作, 但是单链表的限制却很多, 比如不能倒序扫描链表, 解决方法是在数据结构上附加一个域, 使它包含指向前一个单元的指针即可. 那么怎么定义数据结构呢? 首先我们先了解以下链表的分类 1. 链表的分类 链表的结构非常多样, 以下情况组合起来就有…