掌握C语言内存布局:数据存储的智慧之旅

大家好,这里是小编的博客频道
小编的博客:就爱学编程

很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

目录

  • 引言
  • 正文
    • 一、数据类型介绍
      • 1.内置类型
      • 2.自定义类型
      • 3.指针类型
      • 4.空类型(void)
    • 二、数据在内存中的存储规则
      • 1.整型数据在内存中的存储
        • 原码 、反码 、补码
      • 2.整型数据的运算与打印
        • (1)占位符
        • (2)数据范围
        • (3)整型提升
        • (4)数据截断
    • 三、大小端介绍
      • 1.来历
      • 2.模式介绍及效果
      • 3.模式判断
  • 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

引言

本文主要讲述了数据在内存中的存储位置,存储方法以及如何读取内存中的数据。如果你对其有困惑,不妨好好阅读,也许会有新的体会和感悟。
在这里插入图片描述


那接下来就让我们开始遨游在知识的海洋!

正文


一、数据类型介绍

1.内置类型

整型家族

家族成员
int
char
unsigned.int
short.int
long.long
unsigned.short
signed.short
unsigned.long.long
signed.long.long
signed.int
unsigned.char
signed.char

疑惑点:为什么char类型属于整型家族?
解释:这是因为char类型的数据在存储的时候,是以它的ASCLL值进行存储的,本质是一个整型。

浮点型家族

家族成员
float
double

注意:浮点型都是有符号的。


2.自定义类型

组成
数组
结构体.struct
枚举.enum
联合体.union

3.指针类型

组成
一级指针
用来存放内置数据类型变量的地址
二级指针
用来存放一级指针变量的地址

4.空类型(void)

常用于表示函数不需要参数
例:

#include<stdio.h>
int main(void) {printf("hello,world!");return 0;
}

运行结果:
在这里插入图片描述

当然,这常适用于非主函数


二、数据在内存中的存储规则

符号位:对于一个有符号的的数来说,最高位就是符号位,c语言中规定1表示负,0表示正。

1.整型数据在内存中的存储

原码 、反码 、补码

原码
把一个十进制数直接转化为它的二进制,就是这个数的原码。

反码
正数:还是原码
负数:符号位不变,其他位按位取反

补码
正数:还是原码
负数:反码+1

signed.int
负数.十进制
原码.二进制
符号位不变,其他位按位取反
反码
加1
补码
正数.十进制

我们要注意:

  • 对于有符号整型数据:只有屏幕上打印的是原码,而在内存中进行存储和表示的都是补码。

为什么?

序号原因
1.使用补码,可以将符号位和数值域统一处理
2.加减法也可以统一用加法处理(CPU只有加法器)

凭什么这么说?我们可以用一个简单的例子佐证我们的说法
例:

  • 写一个代码打印-1+1的结果

代码:

#include<stdio.h>
int main() {printf("%d", -1 + 1);return 0;
}

运行结果:
在这里插入图片描述

思考讨论
到这里,你可能会想:这不就理应如此吗?但事实上,这是我们c语言设计好的用补码进行运算的结果。不信?你看:如果我们用原码进行计算,我们会惊奇的发现发现:最后的打印结果应为-2。但是这就与常理违背了,-1 + 1 == -2 , 离之大谱!

所以通过这个例子,我们就不难发现:

  • 对于整型数据来说,只有屏幕上打印的是原码,而在内存中进行存储和表示的都是补码的智慧和原因
序号注意
1.原码,反码,补码的概念主要针对有符号的整型家族(signed int或int)类型的数据,而对于其他类型的数据,有其相应的存储方式
2.特殊地:我们把无符号的整型家族可以看做正数(有符号的数)进行处理,只不过这个正数没有符号位

2.整型数据的运算与打印

但是,掌握了以上的知识点之后,我们其实还并不能完全预见和理解整型数据运算屏幕上打印的结果,还得掌握一些占位符的作用,整型提升数据截断数据范围

(1)占位符
占位符作用
%d打印有符号整型数据
%u、%zd打印无符号整型数据

例:

#include<stdio.h>
int main() {int a = 2147483647;int b = 1;printf("%d %u", a + b, a + b);return 0;
}

运行结果:
在这里插入图片描述

思考:为什么同样是a + b,打印的结果确一正一负呢?

  • 这里其实涉及了后文要讲的数据范围,但我们通过这个例子依旧是能够感受到占位符不同所带来的不同打印结果,该题我们在后文再进一步剖析。

(2)数据范围

我们知道:

1.每个数据类型都有其对应的字节长度,1字节 == 8bit 位

详见:

数据类型字节
char1
short(int)2
(long) int4
float4
long long8
double8

那这些bit位是用来干嘛的呢?

2.实际上,这些bit位就是用来存放数字1或0来表示数据大小的。由此我们可以想到:那既然表示数据大小的位数是有限的,那每个类型的数据大小也应该是在一个范围内的。

详见:

数据类型范围
char-128 ~ 127, 0 ~ 255
short(int)- 2^15 ~ 2^15 - 1, 0 ~ 2^16 - 1
(long) int- 2^31 ~ 2^31 - 1, 0 ~ 2^32 - 1

注:有负号的为有符号数据类型数据的范围


那如果一个数据超过了其范围,怎么计算?

我们可以用圆环的思想去考虑:

  • 每一个无符号的数据类型从大到小都是bit位全0–>bit位全1,而到了最大的时候,也就是bit位全1,再加1就会发生数据越位,所有bit位变成全0,然后再由bit全0–>bit位全1,构成了一个头尾相交的圆环。

以unsigned char为例:

11111100
11111111
00000000

等价于:

12
225
0

而每一个符号的数据类型从大到小都是bit位全0–>bit位除了首位全1,而到了最大的时候,也就是bit位除了首位全1,再加1就会变成bit位除了首位全0,然后再变成bit位全1,再加1就会发生数据越位,所有bit位变成全0,然后再由bit全0–>bit位全1,构成了一个头尾相交的圆环。

但是和无符号数据类型不同的是:

  • 有符号的数它的二进制位比无符号的数少了一位数值位,并且我们规定1000…0000000表示的是最小的负数

但我们应注意:

  • 二进制数存储和表示无论是正数还是负数都是采用补码的方式,而只是因为我们把无符号数据看做正数,原码和补码一样,且多了一位数值位才导致了表示和存储方式看起来不同,实际都是一样用补码的形式进行存储和表示。
无符号和有符号数的异同详述
不同无符号数多了一位数值位
相同实际都是一样用补码的形式进行存储和表示
重要规定(有符号的数)1000…0000000表示的是最小的负数

以signed char为例:

10000000
11111111
00000000
01111111

等价于:

127
0
-128
-1

了解这些,我们就可以把上面的例子剖析
例子:

#include<stdio.h>
int main() {int a = 2147483647;int b = 1;printf("%d %u", a + b, a + b);return 0;
}

运行结果:
在这里插入图片描述

疑惑剖析
为什么用占位符%d打印的结果是负数?(1)十进制:2147483648–>二进制(补码):01111111111111111111111111111111;十进制:1–>二进制(补码):00000000000000000000000000000001;相加得:10000000000000000000000000000000(补码)(2)又用%d进行打印,%d是用来打印int类型数据的,所以我们要把相加得的结果转换为原码打印出来(这里要用重要规定)
为什么用占位符%u打印的结果是正数?(1)同上;(2)又用%u进行打印,%u是用来打印无符号整数的,无符号整数的特别之处——就在于我们是把它看作有符号整数中的正数,就导致:它的原码和反码是一样的,所以打印在屏幕上的数就是相加结果的十进制数
对于占位符的思考占位符给了我们一个理解和读取二进制数(补码)的视角方式

(3)整型提升
问题答案
什么叫整型提升?c语言的整型算术运算总是至少缺省(默认)整型类型的精度进行计算。为了获得这个精度,表达式中字符型(char)和短整型(short)在使用之前就被系统自动转换为普通整型(int),这种转换就叫整型提升
整型提升的意义是什么?表达式的整型运算要在CPU的加法器和其他运算器件中进行,而该运算器的操作数的字节长度就为int的字节长度
数据提升的条件和对象发生在小于整型类型的数据类型上

提升规则

对象
有符号数
正数
高位补0
无符号数
看补码
最高位为1则高位补1.否则补0
负数
高位补1

本质就是看补码的最高位是1还是0,是1补1,是0补0


(4)数据截断
问题答案
什么是数据截断?就是一个字节长度较小的数据类型在接收一个字节长度较大的数据类型时只会从字节长度较大的数据的数据低位开始接收,直至填满自己的所有二进制位
会有什么结果?可能会导致数据的丢失,一定会导致字节的减少

熟练掌握这些,我们就基本能预见和理解整型数据运算屏幕上打印的结果,下面就以一些例子来加深和巩固对以上知识的理解

例:

#include<stdio.h>
int main() {char a = 3;//00000011char b = 127;//01111111char c = a + b;//因a和b参加运算,所以要发生整型提升//整型提升规则:高位补符号位(在大部分编译器中,char等价于signed char,即有符号,最高位为符号位,范围为:-128~127;无符号的char类型数据范围为:0~255;//整型提升://00000000000000000000000000000011//00000000000000000000000001111111
//结果00000000000000000000000010000000//截断(发生在高字节类型转化为低字节)://10000000              补码//10000011printf("%d", c);//打印结果为:-126return 0;
}
//也可以用圆环秒解:0 1 2 ~ 126 127 ~-1 -2 -3 ~ -127 -128 ~ 0 1 2 ~~
  • 注释的解析很全,不用再过多解释,对照上面的知识点进行理解

三、大小端介绍

1.来历

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit位。但是在c语言中除了8bit的char之外,还有16bit位的short型,32位的long型(取决于具体编译器);另外,对于位数大于8位的处理器(16bit或32bit),由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排进内存中存储的问题。由此产生了大端和小端。


2.模式介绍及效果

模式(全称)效果
大端字节序存储数据的低位字节存放在高地址
小端字节序存储数据的低位字节存放在低地址

实际效果:

自己模拟
在这里插入图片描述


VS2022上的内存窗口
在这里插入图片描述


3.模式判断

我们可以借助一个2015年百度的笔试题观察大小端的区别

题目:写一个代码,实现大小端的判断

代码:

#include<stdio.h>
int main() {int a = 1;char* p = (char*)&a;if (*p == 1) {printf("是小端\n");} else {printf("是大端\n");}return 0;
}

思路:

序号步骤
1用char*类型的指针一个一个字节地访问int类型变量a的各个字节
2我们可以把a赋值为只有第一个字节有值的整数,这里赋值为1
3前提:我们知道指针访问内存的习惯是从低地址到高地址
4如果*p == 1,说明低地址存放的字节是低位字节,也就是小端存储
5如果*p == 0,说明低地址存放的字节是高位字节,也就是大端存储

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

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

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

相关文章

MySQL NaviCat 安装及配置教程(Windows)【安装】

文章目录 一、 MySQL 下载 1. 官网下载2. 其它渠道 二、 MySQL 安装三、 MySQL 验证及配置四、 NaviCat 下载 1. 官网下载2. 其它渠道 五、 NaviCat 安装六、 NaviCat 逆向工程 软件 / 环境安装及配置目录 一、 MySQL 下载 1. 官网下载 安装地址&#xff1a;https://www.m…

BertTokenizerFast 和 BertTokenizer 的区别

BertTokenizerFast 和 BertTokenizer 都是用于对文本进行标记化的工具&#xff0c;主要用于处理和输入文本数据以供 BERT 模型使用。它们都属于 HuggingFace 的 transformers 库。 主要区别 底层实现&#xff1a; BertTokenizer: 这是一个使用纯 Python 实现的标记器&#xff…

dockerhub上一些镜像

K8s下网络排障工具 https://hub.docker.com/r/nicolaka/netshoot ex kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash # 主机的net ns下运行 kubectl run tmp-shell --rm -i --tty --overrides{"spec": {"hostNetwork": tru…

C语言结构体漫谈:从平凡中见不平凡

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文《1》 结构体的两种声明一、结构…

用行动回应“实体清单”,智谱发布了一系列新模型

1月15日晚间&#xff0c;美国商务部工业和安全局&#xff08;BIS&#xff09;修订了《出口管制条例》&#xff08;EAR&#xff09;&#xff0c;以安全为由在实体清单中分两批增加了25个中国实体。 其中就包括智谱及其子公司&#xff0c;也是国内首家被美国列入实体清单的大模型…

vue3+vite+ts+router4+Pinia+Axios+sass 从0到1搭建

1、使用vite构建项目 npm create vitelatest 填写项目名的时候不能大写 2、跑起来之后配置下 import { defineConfig } from vite import vue from vitejs/plugin-vue import { resolve } from path // https://vite.dev/config/ export default defineConfig({plugins: [vue…

深度学习图像算法中的网络架构:Backbone、Neck 和 Head 详解

深度学习已经成为图像识别领域的核心技术&#xff0c;特别是在目标检测、图像分割等任务中&#xff0c;深度神经网络的应用取得了显著进展。在这些任务的网络架构中&#xff0c;通常可以分为三个主要部分&#xff1a;Backbone、Neck 和 Head。这些部分在整个网络中扮演着至关重…

iOS - 内存对齐

1. 基本的内存对齐 // 对象内存对齐 struct objc_object {// isa 指针 8 字节对齐isa_t isa __attribute__((aligned(8))); };// 定义对齐常量 #define WORD_MASK 7UL // 字对齐掩码 #define WORD_SHIFT 3UL // 字对齐位移 #define WORD_SIZE 8 …

信安大赛单机取证

22年国赛单机取证 Evidence4 先搜索Evidence 找到一个 Evidence4nsOh2.pngf5b9ce3e485314c23c40a89d994b2dc8 Evidence2 之后再一个个找 这个是压缩包格式的 导出来 伪加密 修复一下 Evidence2ZQOo2.jpg9e69763ec7dac69e2c5b07a5955a5868 Evidence3 png的文件 改个宽高 E…

jmeter事务控制器-勾选Generate Parent Sample

1、打开jmeter工具&#xff0c;添加线程组&#xff0c;添加逻辑控制器-事务控制器 2、在事务控制器&#xff0c;勾选Generate parent sample&#xff1a;生成父样本&#xff1b;说明勾选后&#xff0c;事务控制器会作为父节点&#xff0c;其下面的请求作为子节点 3、执行&#…

AOF日志:宕机了Redis如何避免数据丢失?

文章目录 AOF 日志是如何实现的&#xff1f;三种写回策略日志文件太大了怎么办&#xff1f;AOF 重写会阻塞吗?小结每课一问 更多redis相关知识 如果有人问你&#xff1a;“你会把 Redis 用在什么业务场景下&#xff1f;”我想你大概率会说&#xff1a;“我会把它当作缓存使用&…

个人vue3-学习笔记

声明:这只是我个人的学习笔记(黑马),供以后复习用 。一天学一点,随时学随时更新。明天会更好的! 这里只给代码,不给运行结果,看不出来代码的作用我也该进厂了。。。。。 Day1 使用create-vue创建项目。 1.检查版本。 node -v 2.创建项目 npm init vue@latest 可…

react 与 vue 的比较,以及如何选择?

区别 Vue 和 React 都是流行的前端 JavaScript 框架&#xff0c;用于构建用户界面和单页应用&#xff08;SPA&#xff09;&#xff0c;但它们在设计理念、API 设计、生态系统等方面存在一些区别&#xff1a; 核心理念 Vue&#xff1a; 渐进式框架&#xff1a;Vue 被设计为一…

Flutter插件制作、本地/远程依赖及缓存机制深入剖析(原创-附源码)

Flutter插件在开发Flutter项目的过程中扮演着重要的角色&#xff0c;我们从 ​​​​​​https://pub.dev 上下载添加到项目中的第三方库都是以包或者插件的形式引入到代码中的&#xff0c;这些第三方工具极大的提高了开发效率。 深入的了解插件的制作、发布、工作原理和缓存机…

“飞的”点外卖,科技新潮流来袭

一、开篇引入 上个周末&#xff0c;阳光正好&#xff0c;我带着孩子去公园游玩。公园里绿草如茵&#xff0c;花朵绽放&#xff0c;孩子们在草地上嬉笑奔跑&#xff0c;好不快活。玩累了&#xff0c;我们便在草坪上的帐篷里休息。 就在这时&#xff0c;天空中突然传来一阵嗡嗡…

Linux 服务器挖矿木马防护实战:快速切断、清理与加固20250114

Linux 服务器挖矿木马防护实战&#xff1a;快速切断、清理与加固 引言 挖矿木马作为一种常见的恶意软件&#xff0c;对服务器资源和安全构成严重威胁。据安全机构统计&#xff0c;2023 年全球约 45%的 Linux 服务器遭受过挖矿木马攻击&#xff0c;平均每台被感染服务器每月造…

OpenAI推出首个AI Agent!日常事项自动化处理!

2025 年1月15日&#xff0c;OpenAI 正式宣布推出一项名为Tasks的测试版功能 。 该功能可以根据你的需求内容和时间实现自动化处理。比方说&#xff0c;你可以设置每天早晨 7 点获取天气预报&#xff0c;或定时提醒遛狗等日常事项。 看到这里&#xff0c;有没有一种熟悉的感觉&a…

解决vue列表页跳转到详情页,返回列表页时不刷新、保持原来的状态的方法(二)

场景描述&#xff1a; 1、列表页进入详情页&#xff0c;再从详情页返回时&#xff0c;列表页不刷新&#xff0c;比如列表当前分页为第二页&#xff0c;点击进入详情页&#xff0c;再从点击返回按钮&#xff0c;返回到列表页时&#xff0c;列表页保持在第二页。 2、列表页进入编…

闪豆多平台视频批量下载器

1. 视频链接获取与解析 首先&#xff0c;在哔哩哔哩网页中随意点击一个视频&#xff0c;比如你最近迷上了一个UP主的美食制作视频&#xff0c;想要下载下来慢慢学。点击视频后&#xff0c;复制视频页面的链接。复制完成后&#xff0c;不要急着关闭浏览器&#xff0c;因为接下来…

salesforce在opportunity的opportunity products页面增加一个按钮,可以批量删除products

在 Salesforce 中&#xff0c;如果想在「Opportunity > Opportunity Products」列表页面上增加一个“批量删除产品”的按钮&#xff0c;并实现勾选多条产品后统一删除&#xff0c;大体可以考虑以下几种实现思路。由于环境和版本&#xff08;Classic / Lightning&#xff09;…