【C语言】—— 数据在内存中的存储

目录

一、数据类型介绍

二、类型的分类

1.整型家族

2.浮点家族

3.构造类型

4.指针类型

5.空类型

三、原码、反码、补码的概念及计算方法

1. 基本概念

2. 原码、反码、补码的计算方法

四、数据在内存中的存储方式

1.大端字节序存储

2. 小端字节序存储

3. 为什么会存在大小端

4. 设计一个小程序来判断当前机器的字节序

五、专项突破

例题1

例题2

例题3

例题4

例题5

例题6

六、浮点型在内存中的存储

1.浮点数存储的实例

2.浮点数存储规则

3.浮点数如何存、如何取

①如何存

②如何取

 4.详解引入的浮点数存储的实例


一、数据类型介绍

我们所创建的变量会用到以下的类型,这些数据类型决定了变量在内存中占用多少个字节; 

数据类型含义在内存中所占空间大小(32位平台)
char字符数据类型1byte
short(int)短整型2byte
int整型4byte
long(int)长整型4byte
long long(int)更长的整型8byte
float单精度浮点数4byte
double双精度浮点数8byte

sizeof函数:用来计算所常见的不同类型变量所占空间的大小(单位是字节) 

二、类型的分类

1.整型家族

整型家族有符号取值范围无符号取值范围
char (1byte)signed char(-128~+127)unsigned char(0~2^8-1)
short(2byte)signed short(-32768~+32767)unsigned short(0~2^16-1)
int    (4byte)signed int(-2^31~+2^31-1)unsigned int(0~2^32-1)
long (4byte)signed long(-2^31~+2^31-1)unsigned long(0~2^32-1)

2.浮点家族

float --- 精度要求不高的场合;
double --- 精度要求高的场合;

3.构造类型

1. 数组类型      int [10]
2. 结构体类型  struct
3. 枚举类型     enum
4. 联合类型     union

4.指针类型

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

5.空类型

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

三、原码、反码、补码的概念及计算方法

1. 基本概

计算机中的符号数有三种表示方法,即原码、反码和补码,具体如下:

1、原码:就是二进制定点表示法,原码表示法在数值前面增加了一位符号位,正数该位为0,负数该位为1,其余位表示数值的大小,即最高位为符号位,0表示正,1表示负,其余位表示数值的大小。

2、反码:是数值存储的一种,多应用于系统环境设置,如linux平台的目录和文件的默认权限的设置umask,就是使用反码原理。

3、补码:在计算机系统中,数值一律用补码来表示和存储。原因在于使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)。

2. 原码、反码、补码的计算方法

四、数据在内存中的存储方式

1.大端字节序存储

是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

2. 小端字节序存储

是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中;

3. 为什么会存在大小端

        这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。 

4. 设计一个小程序来判断当前机器的字节序

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Check_sys()
{
	//假设存储的数据为 数字1 它在内存中的原码、反码、补码相同 为 00 00 00 01(这里两个为1字节)
	int a = 1;
	//取出a的地址强制转换为char*类型,并且赋给一个char*的指针变量pa,表明此时指针访问空间时是一个字节一个字节的访问
	char* pa = (char*)&a;
	if (*pa == 1)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int main()
{
	int ret = Check_sys();
	if (ret == 1)
	{
		printf("小端存储\n");
	}
	else
	{
		printf("大端存储\n");
	}
	return 0;
}

五、专项突破

例题1

分析下面代码并算出a、b、c的值分别为多少:

#include <stdio.h>
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;
}

引入一个概念 --- 整型提升 

C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为“整型提升”

整型提升的规则:

        1.如果是有符号的数,按照原来的符号位进行提升;

        2.如果是无符号的数,高位直接补0;

看下图:

例题2

 请问a的结果是多少?

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
  char a = -128;
  printf("%u\n",a);
  return 0;
}

例题3

请判断打印的结果是多少? 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);
	return 0;
}

例题4

 判断下面代码会出现什么情况?

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

例题5

结合下面程序,判断a数组的长度?

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
    {
        a[i] = -1-i;
    }
    printf("%d",strlen(a));
    return 0;
}

例题6

 判断下面代码会出现什么情况?

#include <stdio.h>
unsigned char i = 0;
int main()
{
  for(i = 0;i<=255;i++)
 {
    printf("hello world\n");
 }
  return 0;

六、浮点型在内存中的存储

1.浮点数存储的实例

#include <stdio.h>
int main()
{
    int n = 9;
    float *pFloat = (float *)&n;
    printf("n的值为:%d\n",n);
    printf("*pFloat的值为:%f\n",*pFloat);
    *pFloat = 9.0;
    printf("num的值为:%d\n",n);
    printf("*pFloat的值为:%f\n",*pFloat);
    return 0;
}

先看编译器跑出的结果:

 

 n和*pFloat在内存中明明是同一个数,为什么以%f和%d打印出的结果相差这么大呢?

这就要就要搞懂浮点数在计算机内部的表示方法;看下文的浮点数存储规则;

2.浮点数存储规则

根据国际标准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表示指数位。 

 IEEE 754规定: 

IEEE 754对有效数字M和指数E,还有一些特别规定。
前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。至于指数E,情况就比较复杂。首先,E为一个无符号整数(unsigned int)这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即
10001001。 

3.浮点数如何存、如何取

①如何存

②如何取

指数E从内存中取出还可以再分成三种情况:

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

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

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

 4.详解引入的浮点数存储的实例

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霄沫凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值