目录
前言:
学习了这么久的C语言,你知道数据在内存中是怎么存储的吗?那么接下来就和我一起来探究一下数据在内存中究竟是怎么存储的。
数据类型的介绍:
之前我们学习了基本的内置类型:char、short、int、long、long long、float、double。
下面我们来具体分类的学习一下。
类型的基本归类:
整形家族:
char | int |
unsigned char | unsigned int |
signed char | signed int |
short | long |
unsigned short | unsigned long |
signed short | signed long |
浮点型家族:
float | double |
构造类型<自定义类型>:
数组类型 | char arr[ ] |
结构体类型 | struct |
枚举类型 | enum |
联合类型 | union |
指针类型:
int * pi | 整型指针 |
char * pc | 字符指针 |
float * pf | 浮点型指针 |
void * pv | 空指针 |
空类型:
void表示空指针(无类型)。
通常应用于函数的返回类型,函数的参数,指针类型。
整型在内存中的存储:
原码、反码、补码:
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,数值位正数的原、反、补码均相同。
负数原、反、补码的转换规则如下所示:
对于整型来说,数据存放在内存中其实存放的是补码。
为什么?
在计算机系统中,数值一律用补码来表示和存储。原因在于使用补码,可以将符号位和数值域统一处理。
同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
大小端介绍:
大端(字节序)存储模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(字节序)存储模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。
例如:
明确了什么是大小端之后,那现在我们来思考一下为什么会有大小端之分呢?
因为如果一个数值超过一个字节了,要存储到内存中,就有顺序的问题。
一般的小型pc机都是小端存储。
那么接下来我们来做几道练习题吧!
题目:设计一个小程序来判断当前机器的字节序。
思想讲解:
我们可以通过1来判断,如果是1就可以判断为小端字节序存储,如果不是1,那么我们就可以判断为大端字节序存储。
代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 1;
char* p = (char*)&a;
if (*p == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
代码运行截图:
题目:输入的a、b、c分别为多少?
代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char a = -1;
//打印a的分析:
//
//10000000 00000000 00000000 00000001 - 原码
//11111111 11111111 11111111 11111110 - 反码
//11111111 11111111 11111111 11111111 - 补码
//发生截断
//11111111
//以%d打印的时候发生整形提升
//11111111 11111111 11111111 11111111 - 提升后的补码
//11111111 11111111 11111111 11111110 - 反码
//10000000 00000000 00000000 00000001 - 原码
//结果:-1
signed char b = -1;
//10000000 00000000 00000000 00000001 - 原码
//11111111 11111111 11111111 11111110 - 反码
//11111111 11111111 11111111 11111111 - 补码
//发生截断
//11111111
//以%d打印的时候发生整形提升
//11111111 11111111 11111111 11111111 - 提升后的补码
//11111111 11111111 11111111 11111110 - 反码
//10000000 00000000 00000000 00000001 - 原码
//结果:-1
unsigned char c = -1;
//10000000 00000000 00000000 00000001 - 原码
//11111111 11111111 11111111 11111110 - 反码
//11111111 11111111 11111111 11111111 - 补码
//发生截断
//11111111
//以%d打印的时候发生整形提升(由于是unsigned故提升的时候高位补0)
//00000000 00000000 00000000 11111111 - 原码、反码、补码
//结果:255
printf("a = %d, b = %d, c = %d\n", a, b, c);
return 0;
}
代码运行结果:
注意:
%u:是打印无符号整型,认为内存中存放的补码对应的是一个无符号数。
%d:是打印有符号整型,认为内存中存放的补码对应的是一个有符号数。
代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char a = -128;
//10000000 00000000 00000000 10000000
//11111111 11111111 11111111 01111111
//11111111 11111111 11111111 10000000
//截断
//10000000
printf("%u", a);
//11111111 11111111 11111111 10000000 - a
return 0;
}
代码运行截图:
浮点型在内存中的存储:
常见的浮点数:
3.1415
1E10 ---- 1.0 * 10^10
浮点数家族:
float |
double |
long double |
浮点数类型的取值范围限定在:float.h
整数类型的取值范围限定在:limits.h
浮点数的存储规则:
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成下面的形式。
1.(-1)^ S * M * 2^E
2.(-1)^ S表示符号位,当S=0,V为正数,当S=1,V为负数。
3.M表示有效数字,大于等于1,小于2。
4.2^E表示指数位。
例如:
IEEE754规定:
对于32位的浮点数,最高位的1位是符号位S,接着的8位是指数E,剩下的23位位有效位数字M。
float -- 单精度浮点数型
double --- 双精度浮点数型
注意:在M中只存小数点后面的数。
E为无符号整数,存入内存时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。
2.E全为0。
浮点数的指数E等于1 - 127(或者1 - 1023)即为真实值。有效数字M不再加上第一位的1,而是还原为0.*******的小数,这样做是为了表示+- 0,以及接近于0的很小的数字。
3.E全为1。
这时,如果有效数字M全为0,表示+-无穷大(正负取决于符号位S)。
结束语:
这次小编与大家分享了数据是如何在内存中存储的,希望对大家有所帮助,如果想看其他的知识点还请点击小编主页还有其他的知识专栏哦!想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)