C语言进阶数据的存储机制完整版

目录
  • 数据类型
  • 内存窗口
    • 1.地址栏
    • 2.内容
    • 3.文本
  • 整型的存储
  • 原码,反码,补码
  • 补码的意义
  • 大小端模式
  • 不同数据类型存储
  • 浮点数存储机制

数据类型

1.基本内置类型:byte,int ,char, float, double

2.构造数据类型:

数组类型;
结构体类型:struct
共用体(联合类型):union
枚举类型:enum

3.指针类型 :int* p,char* p,float* p,void* p

4.空类型 : void(无类型),通常用于函数的返回类型,函数参数与指针类型。

构造类型又叫自定义类型,在各自参数或者元素类型发生变化就会让他彻头彻尾的改变;而基本数据类型的特点就是不可以再分解为其他类型,基本类型就是自我说明,关于他们的作用就不一一赘述了。

内存窗口

那首先要在调试栏打开内存窗口,并搞清楚怎么观察内存,这是必要的工具

1.地址栏

2.内容

这些密密麻麻的就是内存中的数据,看到这里你可能就会疑惑,不是说内存里存的都是二进制数吗,这些是什么鬼?是的,没有错,但是内存窗口展示内容有限,在有限的范围内,他只能选择以 16 进制的形式展示出来,仅仅是展示而已。

3.文本

这个更是人不人鬼不鬼的其实是他根据内存的数据简单的以文本的格式输出其可能的内容,无价值简直就是意义不明。

整型的存储

不论我们在写代码时创建了个什么东西,他不会居于虚空,存在载体就会占用内存,而空间的大小是根据我们创建的数据的类型而决定的,我们要回到问题最本质的源头,在开辟的内存中到底如何去存储数据?我们不废话直接创建俩个变量看看便知

int main()
{
int a = 5;
int b = -5;
return 0;
}

内存窗口打开我们可以取地址查找 a,b 的数据存储情况:

这里是不是感觉很奇怪,二者为何差异这么大?要搞清楚我们就要继续深入研究。

原码,反码,补码

说整数的二进制有三种表示方法:原码,反码,补码。

整数分为正数和负数,正负数的区别就在于他们二进制32位数的最高位的 0和1代表着符号位,0为正,1为负,其余才是有效位。

正数的原反补三码合一,和他本身是一样的。但是负数就花哨了,负数原码是按照一个数的正,负直接写出来的二进制就是原码。反码在原码基础上,除开符号位进行取反得到。这里强调一下,之前讲过一个操作符:~(按位取反操作符),区别一下他俩,按位取反操作符是针对二进制数每一位全部都取反,包括符号位。补码则是反码的基础上+1得到,比如 -7 这个数的原反补分别为:

10000000 00000000 00000000 00000111 (原)
111111111 111111111 111111111 111111000(反)
111111111 111111111 111111111 111111001(补)

b 的 -5 就是 00000000 00000000 00000000 00000101以补码 11111111 11111111 11111111 11111011 每四个字节为一位化成16 进制就是 0xfffffff3。

补码的意义

既然内存中中存储的是二进制的补码,我们现在不谈现象谈本质,为什么偏偏要是补码呢?
我们要明白一件事就是计算机算减法是相对不容易的,因为CPU里面没有减法器,只有加法器,要算 1-1 时只能算作 1+(-1)。计算机用二进制去计算时,我们会发现,当用原码或者反码去计算根本行不通,只有补码才可以实现。

由此看来,补码的地位是绝对的老大哥,在计算机系统中,数值一律用补码来存储,主要原因是:

1.统一了零的编码

2.将符号位和其它位统一处理

3.将减法运算转变为加法运算

4.两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃

由这里看,加法和减法可以统一起来处理,此外补码和原码相互转换时,其运算过程是相同的,不需要额外的硬件电路。

大小端模式

之前的博客专门讲了大小端存储模式专题,其实大小端的检验也可以用今天的知识来解决:

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

其结果:

不同数据类型存储

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;
}

上面这个代码乍一看就是三个-1,仔细看就会发现char类型后面阴差阳错跟个 -1,-1是整数啊,这时是不是感觉有一丝凌乱?-1的原码为1000(30个0)1,取反+1得到补码111……111(32个1),而 char 只能放 8 个比特位,就意味着会发生截断,,a = 11111111,而我们在vs环境里面 signed char和char是一样的,我们不妨看看运行结果如何:

为什么c会是 255呢?首先要明白为什么b 会是 -1,我们 signed char b在截断后,如果要 以%d形式进行打印,就会发生整型提升,有符号数的最高位会被认为是符号位,而整型提升时会以整型的原符号位进行提升,因为是负数就会全部补成1,再按照补码转原码倒回去会发现结果就是 char a= -1。

同理,c 是无符号数,但也会发生整型提升,无符号数提升通通补 0 ,按照%d 打印时,内存就会认为这是一个有符号数,最高位又会被默认为符号位,最后转换成原码,就会得到 255。

接着上面的思路再来看看这个代码:

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

这个代码也是一个眼见不为实的代码,表面上是打印9个数,实则实在无限的死循环,你发现了吗?聪明的你如果看到 判断条件 i>=0 这个条件,就可能发现端倪,十有八九会死循环,因为不管什么情况都会恒成立。我们来看看运行效果:

当我0进入后很自然的变成了-1,而-1会放到无符号整型,补码是32位全1,而作为无符号整型,最高位不再是符号位,所有位都是有效位,转化为原码是一个巨大的数字,由于满足循环判断条件于是开始欢乐死循环。我们可以根据这些实例总结出相应的经验。

浮点数存储机制

浮点数相对于整型,他的存储机制会更复杂。
浮点数包括float和double,甚至long double,浮点数的表示范围在 float.h中定义。

int main()
{
int  n = 9;
float* pFloat = (float*)&n;
printf("n=%d",n);
printf("*pFloat=%f\n",*pFloat);
*pFloat = 9.0;
printf("n=%d\n",n);
printf("*pFloat=%f\n",*pFloat);
return 0;
}

对上面这个代码,我一开始的觉得打印的是:9,9, 9.0, 9.0,后来发现是我格局小了。

如上结果我们就能明显看出浮点数和整型存储是不一样的。

国际标准IEEE(电气和电子工程协会)754标准,任意一个二进制浮点数V都可以表示成下面的形式:

V=(-1)^S * M * 2^E

1. (-1)^s 表示符号位,s为0表示正,s为1表示负

2. M 表示有效数字,大于等于1,小于2

3. 2^E 表示指数位

对于32位浮点数,最高符号位s,接着 8位是指数E,剩下23位为有效数字M;而64位浮点数,11位是指数 E,剩下的 52 位有效数字M。
这里的M和E还有特殊的规定

IEEE 754规定,在计算机内部保存M时,默认这个数的第1位总是1,因此可以被舍去,只保存后面的小数部分。例如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

我们会把指数位看作是无符号整数,取值在0到255,如果是11位的E,取值在0到2047,但是众所周知,科学记数法里面E是可以出现负数的,所以还有规定就是E在存入时会先修饰一波,给真实值加上一个中间值,对于 8位与11位的E,这个中间数是127和1023,比如 2 的十次方,E就是10,保存成32位浮点数时,必须变成10+127=137,即10001001。E在全0和全1的情况下代表着接近于0的无穷小和无穷大。

我们回到最开始的问题,9的原反补三码合一00000000 00000000 00000000 00001001,E为全0时其真实值是-126,除去S与E,小数部分M为0000……01001,而%f只能打印后6位,这就是为什么打印0.000000。接着pFloat为9.0浮点数进入,对应的二进制为1001.0,科学记数法1.0012^3,S=0,E=3,M=1.001,存入后变成 0 10000010 0010000000000000000000,(S E M),为了方便我们换成16进制计算出是 0x41100000,我以%f取出就是他自己这没什么解释的,困惑的可能是%d的结果,以%d打印就默认为有符号数,变成补码转换出来就是 1091567616。

今天就到这里吧,摸了家人们,更多关于C语言进阶数据的存储的资料请关注我们其它相关文章!

(0)

相关推荐

  • c++基础算法动态DP解决CoinChange问题

    目录 问题来源 问题简述 解决方案 真正的DP 补充--硬币不能重复使用 补充2--不同顺序表示不同组合 结束语 问题来源 这是Hackerrank上的一个比较有意思的问题,详见下面的链接: https://www.hackerrank.com/challenges/ctci-coin-change 问题简述 给定m个不同面额的硬币,C={c0, c1, c2-cm-1},找到共有几种不同的组合可以使得数额为n的钱换成等额的硬币(每种硬币可以重复使用). 比如:给定m=3,C={2,1,3},n

  • 一篇文章带你了解C语言--数据的储存

    目录 前言 数据类型介绍 类型的基本归类 整形在内存中的存储 原码.反码.补码 大小端介绍 浮点型在内存中的存储 前言 前面我们学习了C语言的一些基本知识和基础的语法,想必大家对C语言都有了自己的认识. 当然只是学习这些知识还是不够的,我们需要进行更加深入的学习. 从本章开始,我们将进行C语言进阶阶段的学习,所以难度会有所增加. 数据类型介绍 前面我们已经学习了基本的内置类型: char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更

  • C++动态规划之背包问题解决方法

    本文实例讲述了C++动态规划之背包问题解决方法.分享给大家供大家参考.具体分析如下: 问题描述: 背包的最大容量为W,有N件物品,每件物品重量为w,价值为p,怎样选择物品能使得背包里的物品价值最大? 输入: 10 3   (W,N) 4 5   (w,p) 6 7   (w,p) 8 9   (w,p) 实现代码: #include <stdio.h> #define THING 20 #define WEIGHT 100 int arr[THING][WEIGHT]; /* 背包容量为wei

  • C语言使用DP动态规划思想解最大K乘积与乘积最大问题

    最大K乘积问题 设I是一个n位十进制整数.如果将I划分为k段,则可得到k个整数.这k个整数的乘积称为I的一个k乘积.试设计一个算法,对于给定的I和k,求出I的最大k乘积. 编程任务: 对于给定的I 和k,编程计算I 的最大k 乘积. 需求输入: 输入的第1 行中有2个正整数n和k.正整数n是序列的长度:正整数k是分割的段数.接下来的一行中是一个n位十进制整数.(n<=10) 需求输出: 计算出的最大k乘积. 解题思路:DP 设w(h,k) 表示: 从第1位到第K位所组成的十进制数,设m(i,j)

  • C语言矩阵连乘 (动态规划)详解

    动态规划法 题目描述:给定n个矩阵{A1,A2....An},其中Ai与Ai+1是可以相乘的,判断这n个矩阵通过加括号的方式相乘,使得相乘的次数最少! 以矩阵链ABCD为例 按照矩阵链长度递增计算最优值 矩阵链长度为1时,分别计算出矩阵链A.B.C.D的最优值 矩阵链长度为2时,分别计算出矩阵链AB.BC.CD的最优值 矩阵链长度为3时,分别计算出矩阵链ABC.BCD的最优值 矩阵链长度为4时,计算出矩阵链ABCD的最优值 动归方程: 分析: k为矩阵链断开的位置 d数组存放矩阵链计算的最优值,

  • C语言进阶数据的存储机制完整版

    目录 数据类型 内存窗口 1.地址栏 2.内容 3.文本 整型的存储 原码,反码,补码 补码的意义 大小端模式 不同数据类型存储 浮点数存储机制 数据类型 1.基本内置类型:byte,int ,char, float, double 2.构造数据类型: 数组类型:结构体类型:struct共用体(联合类型):union枚举类型:enum 3.指针类型 :int* p,char* p,float* p,void* p 4.空类型 : void(无类型),通常用于函数的返回类型,函数参数与指针类型.

  • 深度解析C语言中数据的存储

    目录 前言 数据类型介绍 类型的基本归类 整型家族 浮点数家族 构造类型 指针类型 空类型 前言 在VS编译器里有release和debug两种形式,debug包含调试信息,release不包含调试信息,并会对程序进行优化 int main() { int i = 0; int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("hehe\n"); } return

  • C语言中数据如何存储进内存揭秘

    目录 内存简单介绍 整数与字符在内存中的存储 浮点数在内存中的存储 大小端存储模式及简介 总结 内存简单介绍 大家肯定经常听说内存这个词,内存到底是什么呢? 在计算机中,进程都要加载进内存中,也是我们各种数据的流通途径,C语言中,大家肯定都知道指针变量,指针变量中保存的就是内存的地址,那么,什么是内存的地址呢? 内存的单位是字节 对于32位的机器,有32根地址线,每根地址线在寻址时,产生的高低电压分别为0/1,那么32根地址线产生的地址就会是 00000000000000000000000000

  • C语言中数据的存储详解

    目录 1.内置类型 (1)整型数组 (2)浮点型 2.自定义类型 3.指针类型 字符型 浮点型 (一) (二) 总结 数据的存储首先就要说到数据的类型,类型决定了看待内存空间的视角. C语言的数据类型分为内置类型和外置类型 1.内置类型 (1)整型数组 char(字符型).short(短整型).int(整型).long(长整型)(signed 或者 unsigned) (2)浮点型 float(单精度浮点型).double(双精度浮点型) 2.自定义类型 (1)数组类型 此处需要注意的是,去掉数

  • 带你了解C语言的数据的存储

    目录 C语言当中使用的数据类型 使用的类型 整型类 浮点类型 内存当中的存储 原码.反码.补码 大小端 什么是大小端 浮点数的存储 浮点数的存储 浮点数的存储规则 指数 E 从内存当中取出 总结 C语言当中使用的数据类型 使用的类型 char 字符数据类型 short 短整型 int 整形 long 长整型 long long 更长的整形 float 单精度浮点数 double 双精度浮点数 这些里面又分为整型和浮点型 整型类 整型又分为有符号整型和无符号整型,[int] 可以省略掉,就像 sh

  • 详解C语言中数据的存储

    目录 一.类型归类 1.整形家族 2.浮点型家族 3.指针类型 4.空类型 二.类型的意义 三.数据在类型中存储(以整形和浮点型为例子) 1. 关于 存储的基本概念 2.存储模式 四.应用 1. 2. 对于char范围的讨论 总结 一.类型归类 对于基本的c语言数据类型的基本归类 1.整形家族 char (内存存储的为ascall码值,存储为整数) unsigned char// unsigned为无符号关键字 signe char// short unsigned short (int)//

  • C语言数据的存储超详细讲解下篇浮点型在内存中的存取

    目录 前言 浮点型在内存中的存储 浮点数存储的例子 浮点数存储规则 IEEE 754规定 IEEE 754对有效数字M的特别规定 IEEE 754对指数E的特别规定 存入内存是E的规定 从内存取出时E的规定 举例 1 举例 2 举例 3 判断两个浮点数是否相等? 总结 前言 本文接着学习数据的存储相关的内容,主要学习浮点型数在内存中的存储与取出. 浮点型在内存中的存储 常见的浮点数:3.14159.1E10 浮点数家族包括: float.double.long double 类型 浮点数表示的范

  • 关于C语言中数据在内存中的存储详解

    前言 1. 数据类型详细介绍 2. 整形在内存中的存储:原码.反码.补码 3. 大小端字节序介绍及判断 4. 浮点型在内存中的存储解析 一.数据类型介绍 1.类型的基本归类 1.整形家族 char unsigned char signed char short unsigned short [int] signed short [int] int unsigned int signed int long unsigned long [int] signed long [int] 2.浮点型家族

  • C语言进阶几分钟带你理解大小端存储模式

    目录 正片开始 共用体原理 引申一下 字节顺序 大小端存储 共用体判断大小端 正片开始 C语言中数据类型的存储是较为严谨的,一块空间只能存储一种数据类型,要知道内存这个东西,在早期可是非常珍贵的. 尤其对于那些性能不好计算机更是如此,比如 Office1997,操作系统为Windows95 ,奔腾1的cpu,内存只有128M.就这么绿豆点大的存储空间,要想达到节约,利用最大化就必须在同一块空间中存入不同类型数据. 所以共用体的概念就随之产生,将几种不同类型的内容覆盖到同一内存单元,之前在我的一篇

  • C语言数据的存储超详细讲解上篇

    目录 前言 1.数据类型介绍 类型的基本归类 2.整形在内存中的存储 2.1 原码.反码.补码 2.2 大小端介绍 2.2.1 什么是大小端 2.2.2 大端和小端意义 2.2.3 写程序判断字节序 总结 前言 本文开始学习C语言进阶的内容了,进阶内容,是在基础阶段的内容上进行拓展,有的知识点,在基础阶段也已经学过.在进阶内容中,将从更深层次的角度去理解学习,本文主要内容包括: 数据类型详细介绍 整形在内存中的存储:原码.反码.补码 大小端字节序介绍及判断 浮点型在内存中的存储解析 1.数据类型

随机推荐