入门学习计算机第十五天——数据的存储
发布日期:2021-06-28 16:38:48 浏览次数:3 分类:技术文章

本文共 5604 字,大约阅读时间需要 18 分钟。

入门学习计算机第十五天—数据的存储

编译器:Microsoft Visual Studio 2010

前言

记录第十五天学习C语言的博客。

深度剖析数据在内存中的存储

数据类型介绍

内置类型

char 字符数据类型
short 短整型
int 整型
long 长整型
long long 更长的整型
float 单精度浮点数
double 双精度浮点数

类型的意义:

1、使用这个类型开辟内存空间的大小。(大小决定了使用范围)
2、如何看待内存空间的视角。
如何理解2,例子:

int main(){
int a = 10; float f =10.0; return 0;}

调试状态下,调出内存窗口,取出a的地址

在这里插入图片描述
取出f的地址
在这里插入图片描述
int类型和float类型的存储值的方式不同。所以就是看待内存空间的视角不同。

整型家族:

char
unsigned char 无符号的char(范围是0 - 255)
signed char 有符号的char(范围是-128 - 127)
short
unsigned short [int] 无符号的short
signed short [int ] 有符号的short
int
unsigned int 无符号int
signed int 有符号int
long
unsigned long [int] 无符号long
signed long [int] 有符号long

浮点型家族

float

double


构造类型:

  • 数组类型 eg:int [10] char[5]
  • 结构体类型 struct
  • 枚举类型 enum
  • 联合类型 union

指针类型:

int* pi char* pc float* pf void* pv

空类型:

void 表示空类型(无类型)
通常引用于函数的返回类型,函数的参数,指针类型


整型在内存中的存储

int a = 20;int b =-10;

a分配了四个字节的空间,那如何存储?在这里插入图片描述

b也分配了四个字节的空间
在这里插入图片描述

了解以下的概念

计算机中的有符号数有三种表示方法,即原码,反码,补码。

三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。
有符号正数,无符号数原码,反码,补码相同。

原码

直接将二进制按照正负数的形式翻译成二进制就可以。

反码

将原码的符号为不变,其他位依次按位取反就可以得到。

补码

反码+1得到补码。

int a = 20;//a是正整数,原反补相同//00000000000000000000000000010100 - 原码//00000000000000000000000000010100 - 反码//00000000000000000000000000010100 - 补码//二进制转化为十六进制,每四个二进制转换位一个十六进制位//0000 0000 0000 0000 0000 0000 0001 0100//0x00000014int b = -10;//10000000000000000000000000001010 - 原码//11111111111111111111111111110101 - 反码//111111111111111111111111 1111 0110 - 补码//0xFFFFFFF6

对于整型来说,数据在内存中其实存放的是补码

为什么呢?
使用补码,可以将符号位和数值统一处理,同时加法和减法也可以统一处理(CPU只有加法器),此外补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

eg:好比电脑计算1-1,会先转化为1+(-1)

1的补码:00000000000000000000000000000001
-1的补码:11111111111111111111111111111111
相加:100000000000000000000000000000000,33位了,舍弃最高位。
结果是:00000000000000000000000000000000


了解到了a =20 存储在内存中是0x00000014,但是为什么倒着顺序放的?

在这里插入图片描述

再了解以下概念:

大小端:

大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低址中。

小端(存储)模式:是指数据的地位保存在内存的低地址中,而数据的高位,保存在内存的高位中。

通过这样的概念,&a会发现

在这里插入图片描述
处于低位的14存储在了低地址处,所以是小端存储模式。

设置一个代码,告诉我们当前机器的字节序是什么?

int check_sys(){
int a = 1; return *(char*) &a;//只访问a的第一个地址,如果为1,则说明是小端,如果为0,则是大端。}int main(){
int ret = check_sys(); if(ret == 1) printf("小端"); else printf("大端"); return 0;}

以下代码输出的结果是?

int main(){
char a =-1; signed char b = -1; unsigned char c = -1; printf("a=%d b=%d c=%d\n"); return 0;}

输出的结果是-1,-1,255

为什么?

char a =-1;//10000000000000000000000000000001 - 原码//11111111111111111111111111111111 - 补码//因为a只能存储8个字节//11111111 当要输出a为整型时,a要进行整型提升,前面补符号位//11111111111111111111111111111111  所以输出的是-1signed char b =-1;//b与a同理unsigned char c = -1;//11111111111111111111111111111111 - 补码//c也只能存储8个字节//11111111 当要输出c为整型时,c要进行整型提升,但是c是无符号,所以补0//00000000000000000000000011111111 - 无符号数,补码原码相同,所以答案是255。

2、以下代码输出的结果是?

int main(){
char a = -128; printf("%u",a); return 0;}

输出的结果是:

在这里插入图片描述

int main(){
char a = -128; //10000000000000000000000010000000 -原码 //11111111111111111111111101111111 -反码 //11111111111111111111111110000000 -补码 //10000000 char类型只能存储2个字节 8个bit //11111111111111111111111110000000 整型提升,有符号数要补符号位 //但是输出的是十进制无符号的整型 printf("%u",a); return 0;}

所以就是上述结果。

!!!!!!要记住

在这里插入图片描述

在这里插入图片描述

当char a = 128时,char类型是不能存储128,但是可以把128看作127+1,等于-128

int main(){
char a = 128; printf("%u",a); return 0;}

所以输出的结果依然是:

在这里插入图片描述
还有一题:

int main(){
int i = -20; unsigned int j = 10; printf("%d\n", i+j);//按照补码的形式进行运算,最好转化为有符号整数 return 0;}
//11111111111111111111111111101100 -  20的补码//00000000000000000000000000001010  -  10的原码//11111111111111111111111111110110   - 相加//111111111111111111111111111110101   - 反码//1000000000000000000000000000001010   -  原码

结果就是-10

又来一题

int main(){
unsigned int i; for(i = 9; i>=0; i--) {
printf("%u\n",i); } return 0;}

输出的结果是9,8,7,6,5,4,3,2,1,0,死循环。

因为i是unsigned int类型,永远>=0

居然还有题目:

int main(){
char a [1000]; int i ; for(i =0; i<1000; i++) {
a[i] = -1-i; } printf("%d\n",strlen(a)); return 0;}

输出的结果是255

需要结合上图:在这里插入图片描述
当i =0时,结果是-1, i =1,结果是-2以此类推,到了i=127时,结果是-128, i = 129,结果会变成127
再依次类推到 3,2,1,0。strlen遇到’\0’就会停止,由于是char类型的数组,’\0’的ASCII码值为0,所以到0时,strlen就停止了计数。不算上0,一共是255个元素。

555555这个题做不完了:

以下输出的结果是什么:

int main(){
unsigned char i =0; for(i = 0; i<= 255; i++) {
printf("hello\n"); } return 0;}

输出的结果是死循环的hello,unsigned char的取值范围是0~255,所以i<=255,恒成立。

浮点型在内存中存储

常见的浮点数:

3.1415 1E10

浮点数家族:

float
double
long double
浮点数表示的范围:float.h定义

浮点数存储

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

输出的结果

在这里插入图片描述

与想象中区别非常大。为什么呢?需要了解浮点数的存储数据的方式。

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

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

(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位

举例来说十进制9.0,先转化为二进制1001.0 ,再用科学计数法表示为1.001 * 2^3

为正数,所以是(-1)^0 * 1.001 * 2 ^ 3

S为0 ,M为1.001 , E为3

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
综合上面的存入浮点数方法可知,float a =9.0可以表示为:
0100 0001 0001 0000 0000 0000 0000 0000
转换为十六进制
0x41100000
在这里插入图片描述
因为当前机器为小端存储模式,低位数字存在低地址,高位数字存在高地址。

浮点数取出:

当有一个二进制数:0100 0001 0001 0000 0000 0000 0000 0000

当E不为全0或者全1时:

这时浮点数就采用下面的规则表示:即指数E的计算值减去127(或者1023),的到真实值,再将有效数字M前加上第一位的1。

E为全0时:

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

E为全1时:

这时,如果有效数字M全为0,表示±无穷大(正负号取决于符号位S)

再次回到浮点数9.0的问题

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

在这里插入图片描述

int a =9,在内存中二进制为
0 00000000 00000000000000000001001
E为全0,真实值为1-127=-126
转换为十进制数就为(-1)^0 * 0.00000000000000000001001 * 2^(-126),这个值无限接近于0,所以输出的时候为0.000000

因为浮点数9.0在内存中二进制为0100 0001 0001 0000 0000 0000 0000 0000,用十进制的方式输出就是

在这里插入图片描述

转载地址:https://blog.csdn.net/xiaotangyu7dong/article/details/115973890 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:入门学习计算机第十六天——指针进阶(一)
下一篇:入门学习计算机第十四天—结构体,C语言实用调试技巧

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月23日 06时17分52秒