【零基础C语言】内存中的存储

一. 整数在内存中的存储

1.原码反码补码

在计算机中整数在内存中存储的是二进制数

二进制的存储有三种表示的方式:

  1. 原码
  2. 反码
  3. 补码

 这三种表示方式又分为符号位和数值位:

 符号位中0表示正数,1表示负数,最高位被当作符号位,其他为数值位

 如:1  和  -1    64位展示
 1:00000000000000000000000000000001

-1:10000000000000000000000000000001

原码,反码,补码解释:
 如:5
 00000000 00000000 00000000 0000101 - 原码
 01111111 11111111 11111111 1111010 - 反码
 01111111 11111111 11111111 1111011 - 补码

相互转换规则:
 原码 -> 反码 :符号位不变,其他取反。 取反 1->0 或者 0->1
 反码 -> 补码 :+1
 原码 -> 补码 :取反+1
 补码 -> 原码 :取反+1

而对于数据在内存中存储的是补码。
 

2.大小端字节序和字节判断

int main()
{int a = 0x11223344;return 0;
}

 可以看出在内存中存储的是 44 33 22 11 正好和我们的反过来了,这是什么原因呢? - vs底层使用的是小端存储

 什么是大小端?
 首先我们要明白一个数据在内存中存储是有顺序的。

大端存储:数据的低位字节保存在内存的高地址处,高位字节保存在内存的低地址处。

小端存储:数据的低位字节保存在内存的低地址处,高位字节保存在内存的高地址处。
 

 什么是低位字节,我们拿一个数值来类比一下:
 56   6->个位,所以6是低位, 5->十位所以5是高位
 0x11223344 也是如此,  44 -> 低位    11 -> 高位

 

判断当前机器是大端存储还是小端存储

int check()
{int i = 1;return (*(char*)&i); //cahr* 修饰拿到一个字节的存储}int main()
{int ret = check();if (ret == 1)printf("小端");elseprintf("大端");return 0;
}

 练习1

#include <stdio.h>
int main()
{// -1 10000000000000000000000000000001 -原码//    11111111111111111111111111111110 -反码//    11111111111111111111111111111111 -补码char a = -1;// 以%d形式打印,在vs中char是有符号类型,由于是负数,先取反+1,最后结果还是 -1signed char b = -1;// 以%d形式打印,是有符号类型,由于是负数,先取反+1,最后结果还是 -1unsigned char c = -1;// 以%d形式打印,是无符号类型为整数,补码就是原码,但由于unsigned char 范围是 0~255 ,所以打印最大255printf("a=%d,b=%d,c=%d", a, b, c);return 0;
}

 练习2

#include <stdio.h>
int main()
{// -128 - 10000000000000000000000010000000 -原码//        11111111111111111111111101111111 -反码//        11111111111111111111111110000000 -补码char a = -128;char b =  128;// %d - 有符号的十进制输出     %u - 无符号的十进制输出printf("%u\n", a); // a = 4,294,967,168printf("%u\n", b); // b = 4,294,967,168return 0;
}

 

练习3

#include <stdio.h>
int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;   }// -1 -2 -3 -4 -5 .....  -127  128 127 126 .... 0  -1 -2 -3...printf("%d", strlen(a)); // a=225return 0;
}

 练习4

#include <stdio.h>
unsigned char i = 0; //char - -127~128   unsigned char - 0~255
int main()
{for (i = 0; i <= 255; i++){printf("hello world\n");  //死循环}return 0;
}#include <stdio.h>
int main()
{unsigned int i;  //unsigned int -  0~4294967295for (i = 9; i >= 0; i--) // i  min=0 这边的循环就会一直走{printf("%u\n", i);}return 0;
}

 

练习5
x86环境,小端环境

#include <stdio.h>
int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1); //&a - 取出的是整个数组的地址int* ptr2 = (int*)((int)a + 1);printf("%#x,%#x", ptr1[-1], *ptr2);// ptr1 = 4  ptr2 = 0x02 00 00 00return 0;
}

 3.浮点数在内存中的存储

  常见的浮点数: 3.14159  1E10(1.0 * 10^10)
 浮点数包含:float / double  / long dlouble

 浮点数的存储
根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

V = (−1)∗ S M ∗ 2E 

  • (−1)^S 表⽰符号位,当S = 0,V为正数;当S = 1,V为负数
  • M表⽰有效数字,M是⼤于等于1,⼩于2的
  • 2^E 表⽰指数位

 举例;
十进制的5.0 ,二进制是 101.0 ,相当于 1.01*(2^2)
按照格式来写的话,首先是正数 S=0 , M=1.01. E=2。
负数5则是->S = 1, M = 1.01.E = 2。

 

IEEE754规定:

  1. 对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
  2. 对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

IEEE754对有效数字M和指数E,还有⼀些特别规定。
前⾯说过, 1≤ M < 2 ,也就是说,M可以写成 1.xxxxxx 的形式,
其中 xxxxxx 表⽰⼩数部分。IEEE754规定,在计算机内部保存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是可以出现负数的,所以IEEE754规定,存⼊内存时E的真实值必须再加上⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如,2 ^ 10的E是10,所以保存成32位浮点数时,必须保存成10 + 127 = 137,即10001001

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

 1.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,

则其⼆进制表⽰形式为:

 0 01111110 00000000000000000000000


 2.E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还
原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。

 0 00000000 00100000000000000000000


 3.E全为1
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s)

 0 11111111 00010000000000000000000

 题目解析 

#include <stdio.h>
int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n); // n = 9printf("*pFloat的值为:%f\n", *pFloat); // 000000// 9.0 - S = 0, M = 1001 , E = 0000 // V = (-1)^0 * 0.00000000000000000001001 * 2 ^ (1-127)= 1.001*2^(-146)// 二进制的形式 0 10000010 001 0000 0000 0000 0000 0000*pFloat = 9.0;printf("num的值为:%d\n", n); //1091567616printf("*pFloat的值为:%f\n", *pFloat);//9.0return 0;
}

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

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

相关文章

高精度铸铁平台制造工艺有多精细——河北北重机械

高精度铸铁平台制造工艺通常包括以下几个步骤&#xff1a; 材料准备&#xff1a;选择合适的铸铁材料&#xff0c;并确保其质量符合要求。常用的铸铁材料包括灰铸铁、球墨铸铁等。 模具制造&#xff1a;根据平台的设计要求&#xff0c;制造适用的模具。模具一般由砂型、金属模具…

Unity 学习日记 7.用代码让2D角色动起来

下载源码 UnityPackage 目录 1.准备工作 2.显示第一幅图片 3.让乌龟动起来 1.准备工作 步骤&#xff1a; 将乌龟&#x1f422;进行切片 创建一个2D精灵对象&#xff0c;暂时将乌龟&#x1f422;的第一张图片放进去&#xff0c;并调整到合适的大小和位置 然后将精灵对象里…

Python正则表达式之模式修正符,你get了吗?

​大家好&#xff0c;今天我要和大家分享一个Python编程中的神秘武器——正则表达式模式修正符&#xff01;正则表达式&#xff0c;对于很多编程新手来说&#xff0c;可能是一个头疼的问题。但别担心&#xff0c;模式修正符就像是你手中的魔法棒&#xff0c;让你的正则表达式更…

2024创业:开一个抖店,哪怕当副业去做也行!

我是王路飞。 绝大多数人之所以走上创业这条路&#xff0c;原本的理由可能没有这么高大上。 就像我自己当初创业走上电商这条路一样&#xff0c;就一句话&#xff1a;走到绝路了&#xff0c;没办法了&#xff0c;只能闯一把&#xff0c;不让自己饿死。 创业之难&#xff0c;…

流域生态系统水-碳-氮耦合过程模拟

原文链接&#xff1a;流域生态系统水-碳-氮耦合过程模拟https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247598401&idx2&sn4c972ff3a9046094042a0a3dc65e9764&chksmfa8200a6cdf589b01b0af612a5810e6eda02cc9e7f5232db9157ff85de28626a8f4f1878fd9f&…

PTA L2-041 插松枝 代码附注释

人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上&#xff0c;做成大大小小的松枝。他们的工作流程&#xff08;并不&#xff09;是这样的&#xff1a; 每人手边有一只小盒子&#xff0c;初始状态为空。每人面前有用不完的松枝干和一个推送器&#xff0c;每次推送一…

leetcode106从中序与后序遍历序列构造二叉树

目录 1.解题关键2.思路3.变量名缩写与英文单词对应关系4.算法思路图解5.代码 本文针对原链接题解的比较晦涩的地方重新进行说明解释 原题解链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/solutions/50561/tu-jie-…

PHP的IntlChar类:处理Unicode字符的强大工具

PHP的IntlChar类&#xff1a;处理Unicode字符的强大工具 在处理多语言和国际化应用程序时&#xff0c;Unicode字符的解码是必不可少的一环。PHP的IntlChar类为我们提供了强大的工具来解码Unicode字符。本文将深入探讨PHP的IntlChar类&#xff0c;介绍其功能、用法和优势&#x…

基于SpringBoot和Vue的大学生租房系统的设计与实现

今天要和大家聊的是一款今天要和大家聊的是一款基于SpringBoot和Vue的大学生租房系统的设计与实现。 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同…

初识数据库原理:为什么需要数据库?

初识数据库原理&#xff1a;什么是数据库&#xff1f; Chapter1&#xff1a;什么是数据库&#xff1f; 笔记来源&#xff1a;《漫画数据库》–科学出版社 1.1 为什么需要数据库&#xff1f; 文件应用的管理方式&#xff0c;数据会出现重复。 若各个部门各自管理自己一方的数…

【Flutter学习笔记】10.2 组合现有组件

参考资料&#xff1a; 《Flutter实战第二版》 10.2 组合现有组件 在Flutter中页面UI通常都是由一些低级别组件组合而成&#xff0c;当我们需要封装一些通用组件时&#xff0c;应该首先考虑是否可以通过组合其他组件来实现&#xff0c;如果可以&#xff0c;则应优先使用组合&…

Uibot6.0 (RPA财务机器人师资培训第2天 )采购付款——网银付款机器人案例实战

训练网站&#xff1a;泓江科技 (lessonplan.cn)https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981(本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff0…