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//0xfffffff6unsigned 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-- 11111111signed char b = -1;//b -- 11111111unsigned char c = -1;//c -- 11111111printf("%d %d %d", a, b, c);//%d是十进制的形式,打印有符号位的整数//因为abc三个未够4个字节,发生整形提升//a和b 11111111 11111111 11111111 11111111//c    00000000 00000000 00000000 11111111return 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 11101100unsigned int j = 10;//00000000 00000000 00000000 00001010printf("%d", j + i);//11111111 11111111 11111111 11110110//因为%d为有符号十进制输出// 在%d看来都是有符号的 转换为原码》10000000 00000000 00000000 00001010return 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 1001float* 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【redis】redis的认识和安装

目录 1.redis是什么2.Redis的特点3.安装redis4.设置远程连接4.1 开启隧道4.2 可视化客户端连接4.3 开启防火墙 5.redis常见数据类型5.1 redis的一些全局命令5.2 数据结构 6. redis的典型应用---缓存&#xff08;cache&#xff09;6.1 使用redis做缓存6.2 缓存穿透&#xff0c;缓…

angular-mat-select 多选 实现按选择顺序排序

mat-select 正常情况下,多选后,已选项是按列表顺序进行排序,如果我想实现按照点击项目的顺序进行排序,我该如何做呢? [参考网址](Angular order of selected option in multiple mat-select - Stack Overflow) sortComparator是Angular Material中mat-select组件的一个属…

K8S kubeadm搭建

kubeadm搭建整体步骤 1&#xff09;所有节点进行初始化&#xff0c;安装docker引擎和kubeadm kubelet kubectl 2&#xff09;生成集群初始化配置文件并进行修改 3&#xff09;使用kubeadm init根据初始化配置文件生成K8S的master控制管理节点 4&#xff09;安装CNI网络插件&am…

Flutter(八)事件处理与通知

1.原始指针事件处理 一次完整的事件分为三个阶段&#xff1a;手指按下、手指移动、和手指抬起&#xff0c;而更高级别的手势&#xff08;如点击、双击、拖动等&#xff09;都是基于这些原始事件的。 Listener 组件 Flutter中可以使用Listener来监听原始触摸事件 Listener({…

Linux从安装到实战 常用命令 Bash常用功能 用户和组管理

1.0初识Linux 1.1虚拟机介绍 1.2VMware Workstation虚拟化软件 下载CentOS; 1.3远程链接Linux系统 &FinalShell 链接finalshell半天没连接进去 他说ip adress 看IP地址是在虚拟机上 win11主机是 终端输入&#xff1a; ifconfig VMware虚拟机的设置 & ssh连接_snge…

Spring Cloud +UniApp 智慧工地云平台源码,智能监控和AI分析系统,危大工程管理、视频监控管理、项目人员管理、绿色施工管理

一套智慧工地云平台源码&#xff0c;PC管理端APP端平板端可视化数据大屏端源码 智慧工地可视化系统利用物联网、人工智能、云计算、大数据、移动互联网等新一代信息技术&#xff0c;通过工地中台、三维建模服务、视频AI分析服务等技术支撑&#xff0c;实现智慧工地高精度动态仿…

31 对集合中的字符串,按照长度降序排列

思路&#xff1a;使用集合的sort方法&#xff0c;新建一个Comparator接口&#xff0c;泛型是<String>&#xff0c;重写里面的compare方法。 package jiang.com; import java.util.Arrays; import java.util.Comparator; import java.util.List;public class Practice4 {…

单例模式和工厂模式

目录 今日良言&#xff1a;关关难过关关过&#xff0c;步步难行步步行 一、单例模式 1.饿汉模式 2.懒汉模式 二、工厂模式 今日良言&#xff1a;关关难过关关过&#xff0c;步步难行步步行 一、单例模式 首先来解释一下&#xff0c;什么是单例模式。 单例模式也就是单个…

Kubernetes架构和工作流程

目录 一、kubernetes简介 1.k8s的由来 2.为什么用 k8s &#xff1f; 3.k8s主要功能 二、k8s集群架构与组件 1.Master 组件 1.1Kube-apiserver 1.2Kube-controller-manager 1.3Kube-scheduler 2.Node组件 2.1Kubelet 2.2Kube-Proxy 2.3docker 或 rocket 3.配置存储中…

TCP的三次握手和四次挥手······详解

1、三次握手 三次握手是建立连接的过程 如图大致为三次握手的流程图&#xff1a; 当客户端对服务端发起连接时&#xff0c;会先发一个包连接请求数据&#xff0c;去询问能否建立连接&#xff0c;该数据包称为 “SYN”包 然后&#xff0c;如果对方同意连接&#xff0c;那么…

Java实现数据库表中的七种连接【Mysql】

Java实现数据库表中的七种连接【Mysql】 前言版权推荐Java实现数据库表中的七种连接左外连接右外连接其他连接 附录七种连接SQL测试Java测试转换方法类 Cla1类 Cla2类Cla3 最后 前言 2023-8-4 16:51:42 以下内容源自《【Mysql】》 仅供学习交流使用 版权 禁止其他平台发布时…

macOS下Django环境搭建

1. macOS升级pip /Library/Developer/CommandLineTools/usr/bin/python3 -m pip install --upgrade pip 2. 卸载Python3.9.5版本 $ sudo rm -rf /usr/local/bin/python3 $ sudo rm -rf /usr/local/bin/pip3 $ sudo rm -rf /Library/Frameworks/Python.framework 3. 安装P…