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

news2024/12/23 5:47:12

在这里插入图片描述

👦个人主页: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 类型的基本归类

  • 整型家族
char
    unsigned char
    signed char

//后面带括号的可省略
short
    unsigned short (int)   
    signed short (int)

int
    unsigned int
    signed int

long
    unsigned long (int)
    signed long (int)

long long
    unsigned 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 00010100
	
    int b = -10;
	//原码:10000000 00000000 00000000 00001010
	//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反
	//补码:11111111 11111111 11111111 11110110 //反码+1

	return 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       14
	
    int b = -10;
	//原码:10000000 00000000 00000000 00001010
	//反码:11111111 11111111 11111111 11110101 //符号位不变,其他位取反
	//补码:11111111 11111111 11111111 11110110 //反码+1
    //十六进制:ff     ff        ff       f6
	return 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.coloradmin.cn/o/772690.html

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

相关文章

密码学学习笔记(十六 ):Schnorr签名算法

交互式零知识证明 零知识证明(ZKP)就是不会将证据泄露给验证者的知识证明。Schnorr身份认证识别协议是一个交互式ZKP&#xff0c;它满足了完备性、可靠性、零知识性。所谓的交互式ZKP方案通常包含3个步骤&#xff08;承诺、挑战和证明&#xff09;&#xff0c;在文献中通常被称…

传奇新手小白架设单机给玩家充值元宝教程

阿杰今天和大家说说架设的单机如何给玩家和给自已充值元宝的教程 相信有很多玩家都架设过单机吧&#xff0c;架设容易&#xff0c;但是还有一些搞不明白&#xff0c;就是版本里面需 要充值点和积分回馈点才能领取的&#xff0c;那么这些怎么设置呢&#xff1f;今天就教大家两种…

【Express.js】evp-express-cli

evp-express-cli evp-express-cli 是笔者结合自己的实践经验编写的一款 express 手脚架&#xff0c;以一种比较合适的流程构建的 express 架构。 文档 安装用法 命令新建项目运行模板 验证数据库RedisAuthRabbitMQSocketIONacos 开发工具 BabelEsintJestPkgPM2 资源配置日志异…

【Docker】详解docker安装及使用

详解docker安装及使用 1. 安装docker2. Docker镜像操作3. Docker容器操作4.知识点总结4.1 docker镜像操作4.2 docker容器操作4.3 docker run启动过程 参见docker基础知识点详解 1. 安装docker 目前 Docker 只能支持 64 位系统。 systemctl stop firewalld.service setenforce…

Docker 应用容器引擎 (一)

Docker 应用容器引擎 Docker是什么 是一个开源的应用容器引擎&#xff0c;基于GO语言开发并遵循了apache2.0协议开源 是在linux容器里运行应用的开源工具 是一种轻量级的“虚拟机” Docker的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、可移植的、自给自足的…

NOTA WL12,新型双功能整合剂,正电子发射断层扫描 (PET) 显像剂

&#xff08;文章资料汇总来源于&#xff1a;陕西新研博美生物科技有限公司小编MISSwu&#xff09;​ NOTA-WL12试剂 | 基础知识概述&#xff08;部分&#xff09; 英文名称&#xff1a;NOTA-WL12 CAS号&#xff1a;N/A 分子式&#xff1a;N/A 分子量&#xff1a;N/A 规格标准…

【Linux】Docker 基本管理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Docker 基本管理 Docker 概述Docker 核心概念Docker 安装部署Docker 镜像操作Docker 容器操作 Docker 概述 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵…

如何在Windows 10中启用或禁用缩略图预览

文件资源管理器可以在 Windows 10 中显示文件和文件夹的缩略图或图标。 本教程将向你展示如何在文件资源管理器中为你的帐户、所有用户或Windows 10 中的特定用户启用或禁用缩略图预览。 缩略图预览仅在打开并且选择了中等图标、大图标或超大图标文件夹视图布局时显示。 如果缩…

【T1】T1飞跃版红字反冲,提示单据已生成了凭证,不能红冲。但是联查凭证不存在。

【问题描述】 T1飞跃专业版&#xff0c;在经营历程中操作【红字反冲】的时候&#xff0c; 提示&#xff1a;单据已生成了凭证&#xff0c;不能红冲。 但是选中单据&#xff0c;点击联查凭证的时候&#xff0c;又提示【单据没有凭证】。 【解决方法】 针对账套库执行下述语句&…

若依vue -【 33 ~ 】

33 登录日志 系统管理 > 日志管理 > 登录日志 1 应用场景 统计用户的活跃度用户错误输入密码多少次 2 后台实现 &#xff08;1&#xff09;SysLoginController#login&#xff1a;登录 /*** 登录方法* * param loginBody 登录信息* return 结果*/PostMapping("…

(七)「消息队列」之 RabbitMQ 发布者确认(使用 .NET 客户端)

发布者确认&#xff08;Publisher Confirms&#xff09; 发布者确认是一个 RabbitMQ 扩展&#xff0c;用于实现可靠的发布。当在通道上启用发布者确认时&#xff0c;客户端发布的消息将由代理异步确认&#xff0c;这意味着它们已在服务器端得到处理。 0、引言 先决条件 本教程…

Spring、SpringBoot、SpringCloud、SpringCloud Alibaba、Elasticsearch版本对应,附下载地址

1、GitHub Alibaba 发布SpringCloud Alibaba和SpringCloud 、SpringBoot版本 Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot2022.0.0.0-RC2Spring Cloud 2022.0.03.02022.0.0.0-RC1Spring Cloud 2022.0.03.0.02021.0.5.0*Spring Cloud 2021.0.52.6.132021.0.4…

Linux查看某进程所部署的目录路径

1.首先查看系统中正在跑的进程都有什么 ps -ef 2.然后通过抓取你要看的进程名&#xff0c;比如哪些服务 ps -ef | grep xxxxx(服务名) Linux在启动一个进程时&#xff0c;系统会在 /proc 下创建一个以PID命名的文件夹&#xff1b; 在该文件夹下会有我们的进程的信息&#…

【蓝图】p28按键+鼠标点击实现开关门

p28&#xff0c;创建门的蓝图类 actor和组件的区别、门的轴心点修改 创建一个Actor 添加一个静态网格体组件 创建一个门框 同理创建一个门Door 注意&#xff08;当门的中心点不在边角上时&#xff09; 创建一个Scene组件 把物体变换位置 这时只需要旋转Scene就可以旋转…

开发者评价:Serverless 容器最值得推荐的能力是什么?

Kubernetes 作为云原生计算的基础项目&#xff0c;已经在开发者和企业中获得广泛支持。它可以帮助企业加快部署频率、提升应用弹性、优化资源利用率、改善系统可用性。然而其自身复杂性和陡峭的学习曲线依然让一些开发者望而生畏&#xff1b;与此同时&#xff0c;随着企业数字化…

RabbitMQ到底为什么要使用它?

导入 一个技术的衍生必然是为了解决现实出现的问题&#xff0c;在讲这个问题之前我们先了解一下传统开发中关于服务调用出现的问题&#xff08;痛点&#xff09;有哪些&#xff1f; 我们为什么要使用MQ&#xff1f; ①、同步——超时 在多服务体系架构中&#xff0c;必然存在…

掘金量化—Python SDK文档—5.API 介绍(2)

Python SDK文档 5.API介绍 5.6通用数据函数&#xff08;免费&#xff09; python 通用数据 API 包含在 gm3.0.148 版本及以上版本&#xff0c;不需要引入新库 get_symbol_infos - 查询标的基本信息 获取指定(范围)交易标的基本信息&#xff0c;与时间无关. 此函数为掘金公…

C# 动态字典(可以随机实时增删访问,保证先入先出的字典)

如果你有以下需求&#xff1a; 1. 需要对Dictionary进行遍历的同时移除或者添加元素 2. 需要按顺序遍历Dictionary并且保证先入先出 3. 需要即时的获取字典内的元素数量&#xff0c;即时增删 如果你觉得好&#xff0c;请给我的框架点一个免费的star&#xff0c;球球啦 Yueh0607…

如何将视频转换为AVI格式?3个方法轻松转换!

在数字化时代&#xff0c;视频成为了人们记录和分享重要时刻的主要方式之一。然而&#xff0c;不同设备和平台对视频格式的要求千差万别&#xff0c;有时您可能需要将视频转换为特定格式以便于播放或编辑。在本文中&#xff0c;我们将重点介绍将视频转换为AVI&#xff08;Audio…

python实现小波降噪

文章目录 小波分解小波系数小波降噪阈值确定的一些小知识点python 实现小波去噪小波分解 上图为对信号进行3层小波分解,其中,Approximation 为近似小波系数(信号的低频成分),Detail为细节小波系数(信号的高频成分),分解后得到四个小波系数分别为A3,D3,D2,D1。 小波系数 小…