数据在内存中的存储
想要学好编程语言学好语法只是基础,熟悉内存才能对C语言有更加深刻的认识。
一、简单认识内存
首先需要说明,内存是一种物理硬件,计算机中所有程序的运行都在内存中进行。只要计算机开始运行,操作系统就会把需要运算的数据从内存调到CPU中进行运算。当运算完成,CPU将结果传送出来。
与内存相对应的就是外存,内存外存各有特点,下面我来简单罗列一下两者的特点:
内存:容量小,速度快,价格高,掉电后信息不能保存;
外存:容量大,速度慢,价格低,掉电后信息可以保存;
就是由于这些特点,计算机的工作必须由这两部分配合完成,例如:要运行一个exe文件,当你双击文件时这个二进制文件先从外存装载进内存,然后才能被cpu处理。
二、数据在计算机中的存储
我们都知道数据在计算机中存放的形式是二进制,其实数据的存储形式不是简单的二进制,而是一种补码的方式存储的,要了解补码,首先必须得了解原码和反码。
1、原码
最高位为符号位,0代表正数,1代表负数,非符号位为该数字绝对值的二进制表示。
如:
127的原码为0111 1111
-127的原码为1111 1111
2、反码
正数的反码与原码一致;
负数的反码是对原码按位取反,只是最高位(符号位)不变。
如:
127的反码为0111 1111
-127的反码为1000 0000
3、补码
正数的补码与原码一致;
负数的补码是该数的反码加1。
如:
127的补码为0111 1111
-127的补码为1000 0001
4、为什么要采用补码的形式存放数据?
类似于时钟,现在是十一点,如若我们想将时钟的时间调整到一点,我们可以逆时针调整(这是一种减法思想),我们也可以顺时针去调整(这是一种化减为加的思想),而补码要做的,就是将这两种方法统一,为物理硬件让路。
也就是说:省去计算机判断符号位或者说判断+/-运算的麻烦。采用补码表示后,不管是加法还是减法都是加法运算。
例如:一个8位数的"-1+3”运算,如果用原码:10000001+000000011,这样你不能直接相加,否则10000100的结果不伦不类。你需要检查符号位,甚至可能要对符号位和运算符做调整。如果用反码11111110+00000011,这样直接相加的结果不管是00000001还是10000001都不妥,简直不知所云。还是需要适当的处理符号位和运算方式。如果是补码:11111111+00000011=00000010,结果直接就是2。
三、浮点数在计算机中的存储
在C语言中浮点数有float和double两种类型,其中前者占32bit,后者64bit,那么这两种类型都是如何在计算机中存储的呢?
其实不论是单精度还是双精度在存储的过程中都是以一种类似于科学计数法的方式存储的,具体可分为三个部分:
符号位S : 0代表正,1代表为负
指数位E:用于存储科学计数法中的指数数据,该数越大范围
有效数字M:有效数字,该数越大精度越大
则浮点型数据就可以用这种形式表示:s*M*2^E
对于float型,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
对于double型,最高的1位是符号位s,接着的11位是指数E,剩下的52位为有效数字M。
由此可见,double型的数据不管是精度还是范围都要更胜float,所以实际开发中,double型数据的使用率往往更高。
由于浮点数特殊的存放方式,所以一个浮点数的值往往不是准确值,而是有一定的误差范围的,因此在判断两个数是否相等的操作中可能会出现问题,看下面一段代码
#include <stdio.h>
int main(){
float a = 19.0;
float b = a / 7.0;
if (b * 7.0 == a) {
printf("相等!\n");
} else {
printf("不相等\n");
}
return 0;
}
这是运行的结果
因此在判断两个浮点数是否相等的时候应该判断这两个数之差是否在一个极小的范围,若是就相等。看下面一段代码:
#include <stdio.h>
#define N 1e-4
int main(){
float a = 19.0;
float b = a / 7.0;
if (b * 7.0 - a < N && b * 7.0 - a > -N) {
printf("相等, 此处不是严格相等, 而是允许误差\n");
} else {
printf("不相等\n");
}
return 0;
}
这里我们选取了和上面以上的数据,但是却得到了不同的结果
四、大小端问题
何为大小端问题?我们引入下面一段定义,
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
windows系统中数据的存储是小端模式,为了验证此结论我们可以打开vs的内存窗口
我们以int a = 0x11223344;为例,查看它在内存中的存放情况
可以看出它是以一种小端的方式存放的。
或者我们用代码的简单方式来判断一下,代码如下:
#include <stdio.h>
void isBigEnd() {
int num = 0x11223344;
int* p = #
char* p2 = (char*)p;
if (*p2 == 0x11) {
printf("是大端\n");
return;
}
printf("是小端\n");
return;
}
int main(){
isBigEnd();
return 0;
}
运行结果如下:
这就是今天分享的全部内容了,希望大家多多评论,相互提高!!!