【C语言】深剖数据在内存中的存储

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在回炉重造C语言(2023暑假)
✈️专栏:【C语言航路】
🐋 希望大家多多支持,咱一起进步!😁
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、数据类型介绍
      • 1.1 基本的内置类型
      • 1.2 类型的基本归类
  • 二、整型在内存中的存储
      • 2.1 原码、反码、补码
      • 2.2 探讨:为什么整型内存中存的是补码,而不是反码和原码?
  • 三、 大小端介绍
      • 3.1 经典大小端面试题
  • 四、练习
      • 4.1 例1
      • 4.2 例2
      • 4.3 例3
      • 4.4 例4
      • 4.5 例5
      • 4.6 例6
      • 4.7 例7
      • 4.8 例8
  • 五、浮点数在内存中的存储
      • 5.1 浮点数存储规则
      • 5.2 浮点数存储模型
      • 5.3 特别规定
      • 5.4 浮点数存储的例题
        • 5.4.1 例1
        • 5.4.2 例2

一、数据类型介绍

1.1 基本的内置类型

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

类型的意义:

  1. 使用这个类型开辟内存空间的大小(大小决定了其使用范围)
  2. 看待内存空间的视角

1.2 类型的基本归类

  • 整型家族
charunsigned charsigned char//后面带括号的可省略
shortunsigned short (int)   signed short (int)intunsigned intsigned intlongunsigned long (int)signed long (int)long longunsigned long long (int)signed long long (int)
  • char属于整型并不奇怪,因为字符在存储的时候在内存存储的是ASCII值,因为ASCII是整数,所以在归类的时候,字符就属于整型家族。
  • 不管是long long / long / short / int + 变量都等价于signed long long / long /short /int + 变量,但注意:char到底是signed char还是unsigned char完全取决于编译器,常见的char是有符号的
  • 浮点数家族:
float
double
  • 构造类型(又称自定义类型):
数组类型  int[]char[]...
结构体类型 struct
枚举类型 enum
联合类型 union
  • 指针类型
int *p;
char *p;
float* p;
void* p;  //无具体类型的指针
  • 空类型
void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型

二、整型在内存中的存储

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。那么数据在所开辟的内存空间中到底是如何存储的?

比如:

int a = 20
int b = -10;

我们知道int需要开辟4个字节的空间,那么这4个字节的空间到底该如何使用呢?要知道这些首先必须知道什么是原码、反码、补码

2.1 原码、反码、补码

在这里插入图片描述

我们再回头讨论整型在所开辟的空间中到底是如何存储的?

对于整形来说:数据在内存中存储的是二进制序列的补码。

#include <stdio.h>
int main()
{int a = 20;//整数的原码、反码、补码相同//原码:00000000 00000000 00000000 00010100//反码:00000000 00000000 00000000 00010100//补码:00000000 00000000 00000000 00010100int b = -10;//原码:10000000 00000000 00000000 00001010//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反//补码:11111111 11111111 11111111 11110110 //反码+1return 0;
}

接着我们可以通过调试分别查看变量a的内存和变量b的内存:

在这里插入图片描述

我们发现它们是按十六进制数存储的,这是因为如果是二进制的话,显得过于太长了

接下来分别写出a和b的十六进制,我们发现它们是倒着存放的(后面大小端介绍为什么是倒着放):

#include <stdio.h>
int main()
{int a = 20;//整数的原码、反码、补码相同//原码:00000000 00000000 00000000 00010100//反码:00000000 00000000 00000000 00010100//补码:00000000 00000000 00000000 00010100//十六进制:00     00        00       14int b = -10;//原码:10000000 00000000 00000000 00001010//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反//补码:11111111 11111111 11111111 11110110 //反码+1//十六进制:ff     ff        ff       f6return 0;
}

2.2 探讨:为什么整型内存中存的是补码,而不是反码和原码?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

这里可以举个例子帮助大家理解:

在这里插入图片描述

三、 大小端介绍

  • 大端:又称大端字节序存储,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
  • 小端:又称小端字节序存储,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

文字有点干巴,我画图来帮助大家理解:

假设有一个十六进制位:0x 00 11 22 33 44,怎么知道数据的低位和高位呢?举个例子123,个位数的3就是低位,1就是高位,在上面的数据中,44就是低位,00就是高位。

【小端模式 - x86环境】

在这里插入图片描述

【大端模式 - x64环境】

在这里插入图片描述

3.1 经典大小端面试题

问:如何设计一个程序去判断当前的系统是大端还是小端呢?(请用编程实现)

思路:这里我们只要拿1就非常好判断,因为1的十六进制为0x00 00 00 01,在小端的存储模式是0x 01 00 00 00,大端则是0x 00 00 00 01,所以只需要判断第一个字节即可,是1就是小端,是0就是大端。

【代码实现】

#include <stdio.h>
int main()
{int a = 1;// char类型的指针一次只访问一个字节char* p = (char*)&a;if (*p == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}

四、练习

4.1 例1

#include <stdio.h>
int main()
{char a = -1;signed char b = -1;unsigned char c = -1;printf("a = %d, b = %d, c = %d", a, b, c);return 0;
}

【解析】

在这里插入图片描述

整型提升:点击跳转

4.2 例2

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

【解析】

在这里插入图片描述

4.3 例3

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

【解析】

在这里插入图片描述

4.4 例4

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

【解析】

在这里插入图片描述

4.5 例5

#include <stdio.h>
int main()
{int i = -20;unsigned int j = 10;printf("%d\n", i + j);return 0;
}

【解析】

在这里插入图片描述

4.6 例6

#include <stdio.h>
int main()
{unsigned int i;for (int i = 9; i >= 0; i--){printf("%u\n", i);}return 0;
}

【解析】

i的类型是unsigned int,是无符号整型,说明i不可能为负数,因此以上代码发生死循环。

4.7 例7

#include <stdio.h>
#include <string.h>
int main()
{char a[1000];for (int i = 0; i < 1000; i++){a[i] = -1 - i;}printf("%d", strlen(a));return 0;
}

【解析】

strlen只需计算'\0'之前的所有字符,所以只需要找到'\0'即可,其本质就是0。注意:有符号的char的取值范围:-128~127。则-1、-2、-3...-128、127、126、125...1、0。因此一共有127 + 128 = 225
在这里插入图片描述

4.8 例8

#include <stdio.h>
unsigned char i = 0;
//0~255
int main()
{for (i = 0; i <= 255; i++){printf("hello world\n");}return 0;
}

i的类型是无符号char,因此范围:i的范围是0~255,永远都不可能超过225。所以循环里的内容恒成立,所以结果为死循环。

五、浮点数在内存中的存储

5.1 浮点数存储规则

注意:整型和浮点数在内存中的存储是截然不同的!

浮点数在计算机内部的表示方法:
任意一个二进制浮点数可以表示成下面的形式:(-1)S * M * 2E

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

举个例子来说:

十进制的5.0,写成二进制是101.0,就相当1.01×2²。那么,按照上面的格式,就可以得出S = 0(浮点数为正数),M = 1.01E = 2。

有了S、M、E,那浮点数在内存中又怎么表示呢?

5.2 浮点数存储模型

IEEE 754规定:

  • 对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M
    在这里插入图片描述
  • 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M
    在这里插入图片描述

5.3 特别规定

注意:对于有效数字M和指数E,还有一些特别规定:

  • 前面说过,1≤M<2,也就是说,M可以写成1.xxxxxx的形式,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。也就是说,浮点数存入内存时1.xxxxxx中的1可以省略。比如保存1.01的时候,只保存01,剩下位补0。最后等到读取的时候,再把第一位的1加上去
  • 对于E,规定:存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,210E10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001等到读取的时候再减去对应的中间数。

然后,指数E从内存中==取出==还可以再分成三种情况:

  • 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,则其二进制表示形式为:00111111000000000000000000000000
  • E全为0
    这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。
  • E全为1
    这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

5.4 浮点数存储的例题

5.4.1 例1

#include <stdio.h>
int main()
{float f = 5.5f;return 0;
}

【图解】

在这里插入图片描述

5.4.2 例2

#include <stdio.h>
int main()
{int n = 9;float* p = (float*)&n;printf("n的值为:%d\n", n);printf("*p的值为:%f\n", *p);*p = 9.0;printf("num的值为:%d\n", n);printf("*p的值为:%f\n", *p);return 0;
}

【程序结果】

在这里插入图片描述

【图解】

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

初识react

初识react 第一步就给我出个问题版本太低 https://www.cnblogs.com/gslgb/p/16585233.html https://blog.csdn.net/xiangshiyufengzhong/article/details/124193898 第二个问题 便利生成dom 需要绑定key 不要总想着加冒号这不是vue 第三个问题 我p标签包裹 MapList组件 MapLis…

Redis相关配置(3)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis相关配置1、units2、Include3、loadmodule 加载模块4、NET…

创意网页模板免费下载,让你的网站与众不同!

今天给大家带来的网站模板素材&#xff0c;网站类型丰富&#xff0c;包含户外旅行、餐饮、个人网站等等&#xff0c;可以学习和参考其中的布局排版和配色。 ⬇⬇⬇点击获取更多设计资源 https://js.design/community?categorydesign&sourcecsdn&planbbqcsdn772 1、设…

【1++的C++初阶】之vector

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的C初阶】 文章目录 一&#xff0c;什么是vector?二&#xff0c;构造与析构三&#xff0c;vector迭代器的实现四&#xff0c;vector部分重要接口的实现 一&#xff0c;什么是vector? vector…

使用NVIDIA FX Composer验证多纹理合成效果

最近项目上有一个需求&#xff0c;需要将4张带透明通道纹理合成为一张&#xff0c;并且每张纹理指定一个全局透明度。由于纹理过多&#xff0c;合成效果无法保证&#xff0c;为了减少项目的风险&#xff0c;领导希望我先快速验证一下我们讨论的方法是否能完成项目的要求。因此我…

销售易的12年与七个瞬间

导读&#xff1a;企业级没有捷径 12年对一家企业意味着什么&#xff1f; 在消费互联网领域&#xff0c;12年足够长&#xff0c;短短几年内上市的故事过去屡见不鲜。在企业服务的toB领域&#xff0c;产业成熟和企业发展的时间维度被拉长&#xff0c;但故事同样精彩。 2023年7月1…

ylb-接口5产品详情

总览&#xff1a; 1、service处理&#xff08;根据产品id &#xff0c;查询产品信息&#xff09; 在api模块下service包&#xff0c;ProductService接口添加新方法&#xff08;根据产品id &#xff0c;查询产品信息queryById(Integer id)&#xff09;&#xff1a; package …

Python venv 和 virtualenv 虚拟环境的基本使用

1.前言 venv 和 virtualenv 都是搭建虚拟环境的工具&#xff0c;virtualenv 是第三方开源的&#xff0c;而 venv 作为 virtualenv 的一个子集自 Python3.3 开始集成到标准库中&#xff0c;在 virtualenv 的文档中可以看到他们的区别&#xff1a; 没有 app-data 种子方法&#…

Python爬虫——urllib_post请求百度翻译

post请求&#xff1a; post的请求参数&#xff0c;是不会拼接在url后面的&#xff0c;而是需要放在请求对象定制的参数中 post请求的参数需要进行两次编码&#xff0c;第一次urlencode&#xff1a;对字典参数进行Unicode编码转成字符串&#xff0c;第二次encode&#xff1a;将字…

isaac sim添加孔网格

isaac sim仿真和其它仿真实际上一样&#xff0c;对于孔的仿真&#xff0c;是没那么简单的 在此记录一下踩过的坑 1&#xff0c;首先&#xff0c;你需要在soildworks中将你的孔画出来&#xff0c;并导出stl 2&#xff0c;你可以在win10中使用3D画图查看孔的网格&#xff0c;看…

【css】用css样式快速写右上角badge徽标,颜色设置为渐变色

先看效果展示&#xff0c;已公开显示在图片卡片的右上角。 首先是dom代码&#xff1a;需要两个view或者div&#xff0c;public-badge是“已公开”那个矩形&#xff0c;show-signal是右边那个下三角&#xff0c;也就是阴影部分&#xff0c;这样看起来比较有立体感。 <view…

虚拟化技术及实时虚拟化概述

版权声明&#xff1a;本文为本文为博主原创文章&#xff0c;未经本人同意&#xff0c;禁止转载。如有问题&#xff0c;欢迎指正。博客地址&#xff1a;https://www.cnblogs.com/wsg1100/ 文章目录 一、前言二、分时系统三、虚拟化介绍四、虚拟化实现方式及分类模拟器Type2虚拟化…

欧姆龙PLC联网

一、设备信息确认 左上角的为PLC型号,如图该PLC型号为CP1H,不同型号的欧姆龙PLC通讯方面有什么差别呢? 通讯能力和方式不同: 有些型号PLC自带网口,有些则需要扩展(上图中右侧的两个红框内为后扩展的通讯口,扩展模块可以随意组合双网口,双232串口,双485串口都可以)…

JDBC编程连接MySQL数据库遇到的两个错误

在进行java与MySQL数据库进行连接的时候我遇到了两个报错&#xff0c;在一开始的时候遇到的报错是Access denied for user yulinlocalhost (using password: YES)&#xff0c;此时我在网络上搜索发现是密码出现错误的问题&#xff08;出现该问题确实是密码错误&#xff09;&…

【DevOps】Atlassian插件开发指南

本文以Bamboo插件开发为例&#xff0c;记录一下插件开发过程。 一、简介 Atlassian Bamboo 6.9.1 是一款持续集成和持续交付&#xff08;CI/CD&#xff09;工具&#xff0c;支持使用插件扩展其功能。如果需要开发自己的 Bamboo 插件并添加到 Bamboo 中&#xff0c;则可以参考…

设计模式——享元模式

享元模式 定义 享元模式&#xff08;Flyweight Pattern&#xff09;是池技术的重要实现方式。 使用共享对象可以有效地支持大量的细粒度对象。 优缺点、应用场景 优点 可以大大减少应用程序创建对象的数量&#xff0c;降低程序内存占用。 缺点 提高了系统的复杂度&…

spring-IOC

IOC容器 简介 IoC(Inversion of Control)控制反转&#xff0c;是一种基于面向对象编程法则的设计思想&#xff0c;它设计出的程序具有松耦合、更优良的特点。 IoC容器是Spring框架中重要的核心组件之一&#xff0c;贯穿了Spring从出生到成长的整个过程&#xff0c;Spring通过I…

零基础学习,轻松打造物业服务小程序

现如今&#xff0c;物业服务已经成为了人们生活中不可或缺的一部分。为了更好地满足人们对物业服务的需求&#xff0c;许多企业和个人开始开发物业服务小程序&#xff0c;以便提供更加便捷和高效的服务。然而&#xff0c;对于大多数人来说&#xff0c;搭建一个小程序可能需要一…

智能ai绘画软件帮你用科技点亮创意火花

李明&#xff1a;嘿&#xff0c;你听说过ai绘画软件吗&#xff1f;我最近对数字艺术产生了浓厚的兴趣 王磊&#xff1a;当然&#xff01;ai绘画软件真是太神奇了&#xff01;它可以将抽象的文字描述转换成惊人的艺术作品。 李明&#xff1a;是吗&#xff1f;它们绘制的效果怎…

数据库及数据表的相关操作(一)

目录 概念知识一、管理逻辑库与数据表二、常用数据类型和约束2.1 数字数据类型2.2 字符串数据类型2.3 日期数据类型2.4 字段约束 三、索引运行机制和使用原则3.1 创建索引3.2 添加与删除索引3.3 索引的使用原则 概念知识 关系型数据库&#xff1a; 使用了关系模型的数据库系统&…