文章目录

  • 前言
  • 一、数据在内存中的存储
    • 1.基础
      • (1)推导中使用的调试操作
      • (2)大小端的概念
      • (3)整形在内存中的存储
    • 2.浮点型在内存中的存储
  • 二、基本数据类型
    • 1.指针中的简单应用
    • 2.整型提升和算术转换
  • 总结

前言

本文采用的图片全为深色模式下截屏,请放心观看


一、数据在内存中的存储

1.基础

(1)推导中使用的调试操作

这一块懂哥们可以先跳过
先贴一下讲解时使用的代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int m = 10;int n = -10;return 0;
}

在笔者使用的VS2019的这个环境中,我们先同时按下ctrl和F5(笔记本用户可能需要同时按下Fn,目的是开始运行这个程序,但是不进行调试
然后我们按照调试—>窗口—>内存—>内存1(1)的顺序点击

最后打开这个界面

盯准主界面的这个小箭头,它代表程序运行到哪里了,按下F11(笔记本用户可能需要同时按下F11)让程序执行完m和n的初始化
最后我们在地址这一栏里填写“&n”然后按回车

最上面的这一行就是对应地址里存储的东西了
众所周知一个整形的大小是4个字节,一个字节对应8个比特位,但是直接把储存一个整型的二进制位全部打印出来的话太麻烦了,所以你在上面看到的都是16进制位
根据24 =161 是可以推出8个比特位(1个字节)对应2个16进制位的
类似的我们也可以根据23 =8推出3个比特位对应一个8进制位
但如果我们不知道这样推呢
我们先随便在显示的地址里面揪出两个相邻的,如下图:

打开Windows自带的计算器,选择程序员模式,如下图:

注意:
HEX代表16进制;DEC代表10进制;OCT代表8进制;BIN代表二进制
我们选择HEX把上面的两个地址相减

然后点击DEC将结果转化为10进制

巧啊!很巧啊!在内存中窗口里面,你可以看见这些数字是成对的,数一下可以发现一行正好有28对,如下图:

也就是说每一对数字都对应着一个内存单元,也就是一个字节
那么对于整形,我们只需要看前4对,就能知道变量对应的地址里面存储的内容了
如下图:

(2)大小端的概念

先贴一段代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int a = 291;//16进制的123return 0;
}

内存窗口如下:

仔细观察一下上图,可以发现:
以字节为单位,数据的低位储存在低地址中,数据的高位储存在高地址中,这种数据存储的方式就是在我们使用的计算机上的常用的存储方式,叫做小端存储;而一些服务器上可能把数据的高位存储在低地址中,数据的低位存储在高地址中,这种方式被定义为大端存储。
(有些ARM芯片可还可以由硬件选择是大端模式还是小端模式)

(3)整形在内存中的存储

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int a = 10;int b = -10;return 0;
}

在上述代码中,把10转化为2进制并补足32个2进制位,结果如下:
0000 0000 0000 0000 0000 0000 0000 1010
这个就是原码,对于无符号整型来说这32位全用来表示数值的大小;对于有符号整型来说最左边那位是符号位,0表示正数,1表示负数,所以-10的原码长这样:
10000000 00000000 00000000 00001010
对于正整形和无符号整型,它们的原码,反码,补码都相同,对于负整形来说,原码按位取反(0变1,1变0)得到反码,反码加1得到补码
-10的反码:01111111 11111111 11111111 11110101
-10的补码;01111111 11111111 11111111 11110101
数据存储时用的都是补码,对整形使用位操作符的时候,本质就是在对它们的补码进行操作,但是我们将结果打印出来的时候会把补码转化为原码来输出

2.浮点型在内存中的存储

首先,任意一个二进制浮点数V可以表示成这种形式:
a=(-1)S * M * 2E 其中S,M和E都是正整数:
其中==(-1)S 是符号位==,S的取值只有0和1;“M * 2E ”这部分类比十进制里的科学计数法理解就可以
举个例子(十进制转换为二进制):-5.0=(-1) * 1.01 * 22 ,这里的S等于(-1),M等于1.01, E等于2
IEEE(电器和电子工程协会)754规定,对于32位的浮点数,最高的一位是符号位S,接着的8位是指数E,剩下的23位为有效数字M;
对于64位的浮点数,最高的一位是符号位S,接着的11位是指数E,剩下的52位为有效数字M;

关于M的特殊规定:
在二进制中,M肯定是大于等于1且小于2的,既然M的整数部分默认为一,计算机就不把这以为往内存里存储了,只保留后面的小数部分,取出来的时候加回来就可以了,
关于E的特殊规定:
E是个无符号整数,存入内存的E的真实值必须加上一个中间数:对于32位的浮点数,中间值为127,对于64位的浮点数,这个中间值是1023,这是存进去时的规定
取出来的时候要分成三种情况:
(1)当E不全为0或者不全为1时:重复上述操作的相反操作,E先减去127,M再加上第一位的1,就得到真实值了
(2)E全为0:这时浮点数V表示一个接近于0的一个极小的数字,有效数字M不再加上第一位的1
(3)E全为1:浮点数V表示正负无穷大

二、基本数据类型

以下为一些比较常见的类型的大小,具体代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{printf("char=%d\n", sizeof(char));//大小为1字节printf("short=%d\n", sizeof(short));//大小为2字节printf("int=%d\n", sizeof(int ));//大小为4字节printf("long=%d\n", sizeof(long));//大小为4或8字节printf("long long=%d\n", sizeof(long long ));//大小为8字节printf("float=%d\n", sizeof(float));//大小为4字节printf("double=%d\n", sizeof(double));//大小为8字节return 0;
}

运行结果:

注意“long"类型的大小不一定和上述运行结果相同(显示为4),目前规定大小:long>=int,一般来说4或者8都有可能

1.指针中的简单应用

我觉得最常见的应用还是体现在指针相关的程序中,先看一段代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7 };int* p1 = &arr1;char arr2[] = "abcdef";char* p2 = &arr2;printf("arr1=%p\n", p1);printf("arr+1=%p\n", p1+1);printf("arr2=%p\n", p2);printf("arr2+1=%p\n", p2+1);return 0;
}

运行结果:

从上个程序里我们得知int类型的数据存储时占用的大小为4个字节,换算出来
是32个比特位(二进制位)
然而我们要知道上面打印出来的地址已经经过简化了,显示的不是冗长的2进制位而是换算出来的16进制位
16进制位里面1到9还是1到9,但10到15的这几个数字用A,B,C,D,E,F来表示,根据指向的这一个内存单元大小为1字节
再经过观察之后就可以发现:整型数组arr1中,(arr1+1)对应的地址比(arr1)对应的首地址要多出一个整形的大小;相应地,字符型数组arr2中 ,(arr2+1)对应的地址也要比(arr2)多出一个字符类型的大小

2.整型提升和算术转换

这类应用还是在做题的时候比较常见,先来看一张图:

一般来讲,在使用操作符(+ - * /比较多)的时候,操作数需要类型相同,如果类型不同,在上图中位次较低的类型会沿箭头方向转化成位次较高的类型进行运算
同样需要遵守几条规则:
有符号整形进行整型提升时,高位补充符号位;无符号整型提升时高位补0(char类型也有符号)
这是低位向高位转化的过程,如果非要把高位的数据类型转换为低位的话,直接截断就可以了
这里得用绝对值大一点的数举例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{int b = -1000;//原码为1000 0011 1110 1000,补码为0111 1100 0001 1000char a = 0;a = b;printf("%d", a );
}

这里把int类型的数据强行塞进char类型里面,由于char类型大小是8个比特位,所以存进去的只有“0001 1000”这8位,剩下的高位被截断了
剩下的这些是补码,虽然它曾经表示一个负数,但是现在它表示符号的最高位是0,所以“0001 1000”,会被当作整数打印出来,理论上讲打印出来的是十进制的24
实际的运行结果如下图:

其他相似的问题也可以通过类似的思路来解答


总结

一般刷题的时候就总是看见出题人把先不同类型的数据加减乘除,把内存中的补码弄得一团糟,然后可能用%d,%f,%u等形式打印出来,如果题目是要求我们分析打印出来的结果的话,我们结合整型提升或者算术转换,按对应的规则把补码解读出来就可以了
最后感谢你能看到这里,这篇博客啰啰嗦嗦写了很多,感谢支持!


我们仍未知道那天所见的数据是怎么存放在内存中的相关推荐

  1. 10677 我们仍未知道那天所看见的花的名字

    10677 我们仍未知道那天所看见的花的名字 时间限制:1000MS  内存限制:65535K 题型: 编程题   语言: 无限制 Description     芽间.仁太.波波.安鸣.雪集.鹤见是 ...

  2. SCAU 10677 我们仍未知道那天所看见的花的名字

    10677 我们仍未知道那天所看见的花的名字 时间限制:1000MS  内存限制:65535K 题型: 编程题   语言: 无限制 Description 芽间.仁太.波波.安鸣.雪集.鹤见是昔日孩童 ...

  3. ACM复习(42)10677 我们仍未知道那天所看见的花的名字

    Description 芽间.仁太.波波.安鸣.雪集.鹤见是昔日孩童时期总是一起结伴同玩的6位好朋友.自从小时候的一次意外后,大家的关系渐行渐远. 随着时间的流逝,大家都为了自己的生活和理想各奔东西. ...

  4. 未闻花名怎么用计算机,未闻花名(我们仍未知道那天所看见的花的名字)攻略...

    ----攻略主要来自未闻花名吧 沐雪婼非,个人按攻略玩了全结局,对一些错误和翻译名字不准确的地方修正了下,按本攻略不能全CG收集,但全结局是可以的 大概流程: 面码 normal ending+宿海 ...

  5. 我们仍未知道那天踩的MultipartFile file为null的大坑是为什么

    前天前端小哥暗搓搓地戳我说,文件上传报错了!赶紧改改好! 一想到这个项目已经发布正式地址了,当即*一紧,赶紧本地试了一下,后台接收的参数为空,但是一看代码已经一个多月没有修改了,当即就用怀疑的眼神看向 ...

  6. 命名实体识别 NER 论文综述:那些年,我们一起追过的却仍未知道的花名 (一)...

    点击上方,选择星标或置顶,每天给你送干货! 阅读大概需要24分钟 跟随小博主,每天进步一丢丢 作者: 龚俊民(昵称: 除夕) 学校: 新南威尔士大学 方向: 自然语言处理和可解释学习 知乎: http ...

  7. 索骥馆-OFFICE系列之《EXCEL数据分析之道:让你的数据更有说服力》扫描版[PDF]

    结合大量的具有实用价值的实际案例,来介绍利用excel快速制作各种统计分析报表和图表的基本方法和技巧,可使您的excel使用水平提升到一个新的层次,使您的分析报告更加具有说服力,更加引人注目. 本书介 ...

  8. 林铭的鸿蒙灵珠,终于知道了《儒道至圣》中方运和《真武世界》中天元谁更厉害了!...

    原标题:终于知道了<儒道至圣>中方运和<真武世界>中天元谁更厉害了! 哈喽,大家好,我是老罗,今天给大家盘点<儒道至圣>中方运和<真武世界>中天元谁更厉 ...

  9. 苹果HomePod 2月9日上市 何时登陆中国仍未知

    ▼ 点击上方蓝字 关注网易智能 聚焦AI,读懂下一个大时代! [网易科技讯 1月24日消息]据9to5Mac报道,苹果公司宣布,售价349美元的智能音箱HomePod将于2月9日上市,顾客可以在周五之 ...

最新文章

  1. Linux下HOOK动态链接库中API的方法
  2. 某游戏在华为鸿蒙,部分安卓游戏在华为鸿蒙 OS 上运行,被识别成使用 PC 端模拟器...
  3. phonegap在android中如何退出程序
  4. [kubernetes] 资源管理 --- 资源预留实践
  5. jenkins war包_Jenkins的安装和部署(jenkins教程)
  6. 工作320:uni-预加载问题
  7. JS 与Flex交互:html中的js 与flex中的actionScript通信
  8. 火狐导cookie文件没反应_效率指南|实操区分FireFox火狐的国内版和国际版
  9. 中国科学家突破二氧化碳人工合成淀粉技术
  10. Promise源码学习(2)
  11. 程序员接私活平台_程序员去哪儿接私活?我系统总结了15个国内平台,绝对靠谱...
  12. 数据库智能运维高级探索与最佳实践
  13. CPU高获取其线程ID然后分析
  14. 前端代码的整洁之道 | 技术头条
  15. 8-7/8 java/redis 客服端
  16. python from import 和 import 区别_python import和from import的区别
  17. win10卓越性能模式
  18. C语言有负号的除法以及求余运算规则
  19. 用c#语言制作点歌程序,c#实现KTV点歌系统
  20. p=p->next 是什么意思

热门文章

  1. Delphi 的TZipFile压缩文件自定义(去掉盘符)
  2. day3分支和循环作业
  3. 四 测光模式与曝光仪
  4. html页面调用js文件里的函数报错onclick is not defined问题(作用域问题)
  5. OwlCarousel使用
  6. 合并视频的方法有哪些?
  7. 多媒体系统之MediaCodec基本原理及使用
  8. ISE14.7使用教程(一个完整工程的建立)
  9. linux lun分区,Linux服务器新增LUN而不需重启的实现
  10. 京东手机金机奖揭晓,国内最强5G生态联盟成立