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

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

编译器: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
//0x00000014
int 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  所以输出的是-1
signed 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,用十进制的方式输出就是
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值