C语言 ——[数据在内存中的存储] 深度理解



一、数据类型

1.内置类型:

  • 整型
       - char (可单独列为字符类型)
       - short
       - int
       - long
       - long long
       - unsigned char
       - …
  • 浮点型
       - float
       - unsigned float
       - double
       - unsigned double

char是 signed char 还是unsigned char ?

  • C语言标准没有规定,取决于编译器 - 一般是signed
  • 规定了其他内置类型为signed

2. 构造类型(自定义类型)

  • 数组类型 - arr[ ]
  • 结构体类型 - struct
  • 枚举类型 - enum
  • 联合体类型 - union

3.指针类型

  • int* p
  • float* p
  • void* p

4.空类型void的应用

  • 函数的返回类型
  • 函数的参数
  • 指针类型void* p

不同类型的意义是什么?(重点 - 要深刻理解)

  1. 分配存储数据的内存空间大小不同(大小决定了使用范围)
  2. 读取内存中所存储数据方式不同
  3. 提高内存空间利用率

二、整型的存储

为什么char可以归为整型类型?
存储和读取数据的方式相同

计算机中,整数的表示方法:

补码转换为原码的方式:

  • 补码 _ (取反+1) _ 原码(同原码转换为补码的方式一样)
  • 补码 _ (-1 取反) _ 原码

1、整型存储的方式

  • ‘字符’ - 以ASCII码的形式 - 在内存中存储
    通常用char来存储字符 - 提高内存空间利用率
  • 整数(4byte) - 二进制补码 - 在内存中存储
    超出char 和 short 类型范围的整数 - 截断后存储
  • 整型存储数据的补码 / ASCII码

内存中为什么存放补码?

2、整型的读取方式

  • ‘字符’ :数据被视为ASCII码
  • 有符号数:符号位 + 数值位
  • 无符号数:数值位

signed和unsigned存储的方式相同,读取数据的方式不同

内存单元和地址
内存单元: 大小一个字节
地址: 内存单元的编号
在这里插入图片描述

整型变量在内存中的存储
在这里插入图片描述
a 、b在内存中以补码的形式存储,整型的4个字节存储顺序有两种模式 - 大端和小端,此处为小端储存模式

3、大小端字节序

1、什么是大小端?
两种储存模式

  • 大端字节序: 数据的低位储存在内存的高地址,数据的高位储存在内存的低地址 - 符合我们的阅读习惯
  • 小端字节序: 数据的低位储存在内存的低地址,数据的高位储存在内存的高地址

2、为什么有大小端之分?

  • 在计算机中,通常以字节为单位存储数据,每个地址对应一个字节。
  • 16位和32位的处理器中,寄存器宽度大于一个字节,为提高效率,合理安排字节的存储顺序

3、设计程序判断当前机器的字节序

#include<stdio.h>
int check_sys()
{
	int a = 1;
	//00000000 00000000 00000000 00000001                          
	char* p = &a;//取首字符地址 - 低地址
	return *p;//低地址存01 - 返回1;低地址存00 - 返回0
  //return *(char*)&a;
  //返回1 / 0;
}
int main()
{
	int ret = check_sys();
	if(ret == 1)
	{
		printf("大端");
	}
	else
	{
		printf("小端");
	}
	return 0;
}

4、代码理解

理解1

#include<stdio.h>
int main()
{
	//1、
	char a = -1;//VS 默认char 为 signed char - C语言标准未规定
	//存储方式
	//a:11111111
	signed char b = -1;
	//b:11111111
	unsigned char c = -1;
	//c:11111111

	//读取方式
	// %d打印 - 整型提升
	//11111111 11111111 11111111 11111111 : -1
	//00000000 00000000 00000000 11111111 : 255
	printf("a = %d, b = %d, c = %d\n", a, b, c); 

	//2、
	char A = -128;
	//原码   - 10000000 00000000 00000000 10000000
	//反码   - 11111111 11111111 11111111 01111111
	//补码   - 11111111 11111111 11111111 10000000
	//截断后 - 10000000
	char B = 128;
	//原反补 - 00000000 00000000 00000000 10000000
	//截断后 - 10000000

	//A 、B 的类型是signed char
	//整型提升:11111111 11111111 11111111 10000000
	//         4294967168
	//再以%u的格式打印
	printf("A = %u, B = %u\n", A, B);//A == B == 4294967168
		
	//3、
	int i = -20;
	//-20
	//10000000 00000000 00000000 00010100 - 原码
	//11111111 11111111 11111111 11101100 - 补码
		
	unsigned int j = 10;
	//10
	//00000000 00000000 00000000 00001010 - 原反补
		
	//i + j
	//11111111 11111111 11111111 11110110 - i + j(补码)
		
	printf("i + j = %d\n", i + j);
	// %d 格式打印
	//10000000 00000000 00000000 00001010 - i + j(原码) · -10
		
	printf("i + j = %u\n", i + j);
	// %u 格式打印
	//11111111 11111111 11111111 11110110 - i + j(原反补) · 4,294,967,286
	return 0;
}

理解2

#include<stdio.h>
int main()
{
	unsigned int i = 0;
	//unsigned int的值的范围 0 到 4294967295
	for (i = 9; i >= 0; i--)
	{
		printf("%u", i);
	    //9 8 7 6 5 4 3 2 1 0 ··· 4294967295 ··· 3 2 1 0 ··· 循环
	}
	return 0;
}

理解3

#include<stdio.h>
int main()
{
	char a[1000];
	//char 的值的范围 -128 到 127
	int i = 0;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
		//-1 -2 -3 ··· -128 127 128 ··· 3 2 1 0;
	}
	printf("%d\n", strlen(a));//找字符串结束标志 '\0' -ASCII码 - 0
	//255
	return 0;
}

理解4

#include<stdio.h>
int main()
{
	unsigned char i = 0;
	//unsigned char 的取值范围 0 到 255
	for (i = 0; i <= 255; i++)
	{
		printf("love\n");//死循环
	}
	return 0;
}

三、浮点数的存储

1、浮点数的二进制表示

  • 整数部分:除 2 取余
  • 小数部分:乘 2 取整
  • 科学记数法:同十进制
  • 5.5 = 101.1 = 1.011 × 2 2 5.5 = 101.1 = 1.011 \times 2 ^ 2 5.5=101.1=1.011×22

二进制精确表达一个十进制的浮点数很难

  • 5.21 = 101.00110101110000101000111101011100001010001111010111 5.21 = 101.00110101110000101000111101011100001010001111010111 5.21=101.00110101110000101000111101011100001010001111010111

综上,任意一个浮点数可表示为

  • V = ( − 1 ) S × M × 2 E V = (-1)^S \times M \times 2^E V=(1)S×M×2E

S - 符号位 - 取 0 / 1
M - 有效数字 ( 1 ≤ M < 2 ) (1 \leq M < 2) (1M<2)

  • 理解: 十进制(decimal): 0.4 = 4 × 1 0 − 1 0.4 = 4 \times 10^{-1} 0.4=4×101
        二进制(binary): 0.25 ( d e c i m a l ) = 0.01 ( b i n a r y ) = 1 × 2 − 2 0.25(decimal) = 0.01(binary) = 1 \times 2^{-2} 0.25(decimal)=0.01(binary)=1×22

E - 指数 - 取整数(负数、0、正数)

2、IEEE754标准

  • 单精度浮点数float(32bit)的储存方式 在这里插入图片描述

  • 双精度浮点数double(64bit)的储存方式在这里插入图片描述

3、浮点型的存储

计算机中存储的 M 与实际的 M 是不同的

  • 计算机存储的 M 是1.xxxxxx 中的 xxxxxx
    ( 1 ≤ M < 2 ) (1 \leq M < 2) (1M<2),为提高精度,扩大取值范围,舍去第一位 1,只储存xxxxxx部分。

计算机中存储的 E 与实际的 E 是不同的

  • E 存储 E_{存储} E存储是一个 unsigned int 类型的整数
  • float : E 存储 = E 真实 + 127 E_{存储} = E_{真实} + 127 E存储=E真实+127
  • double : E 存储 = E 真实 + 1023 E_{存储} = E_{真实} + 1023 E存储=E真实+1023

计算机中:

  • 0 ≤ E ( 8 b i t ) ≤ 255 0 \leq E(8bit) \leq 255 0E(8bit)255
  • 0 ≤ E ( 11 b i t ) ≤ 2047 0 \leq E(11bit) \leq 2047 0E(11bit)2047
    考虑到指数E可以取负数,规定 E 存储 = E 实际 + 中间数 E_{存储} = E{实际} + 中间数 E存储=E实际+中间数

4、浮点型的读取方式

  • E 存储 E_{存储} E存储的读取方式有三种情况

① E不全为 1 / 0

  • 按正常转换得到 E 真实 E_{真实} E真实 M 真实 M_{真实} M真实

② E全为0

  • E 存储 = 255 E_{存储} = 255 E存储=255       E 真实 = 1 − 127 = − 126 E_{真实} = 1 - 127 = -126 E真实=1127=126
  • E 存储 = 2047 E_{存储} = 2047 E存储=2047      E 真实 = 1 − 1023 = − 1022 E_{真实} = 1 -1023 = -1022 E真实=11023=1022
  • ( 0 < M < 1 ) (0 < M < 1) (0<M<1),M 第一位补 0 得到真实值

③ E全为1

  • E 真实 = 128 E_{真实} = 128 E真实=128      E 真实 = 1024 E_{真实} = 1024 E真实=1024
  • 若 M 为全 0,表示 + ∞ +\infty + − ∞ -\infty

浮点型变量在内存中的存储
在这里插入图片描述

5、代码理解

#include<stdio.h>
int main()
{
	int n = 9;
	//存储:00000000000000000000000000001001
	float* p = (float*)&n;
	printf("n = %d\n", n);//以整型的方式 - 读取
	//n = 9 
	printf("*p = %f\n", *p);//以浮点型的方式 - 读取
	//S = 0; E = 0; M = 0.00000000000000000001001
	//*p = 0.00000000000000000001001 * 2^(-126)
	*p = 9.0;//以浮点型的方式 - 存储
	//9.0 == 1001.0 == 1.001 * 2^3
	//S = 0; E = 3 + 127; M = 001;
	//存储:01000001000100000000000000000000
	printf("n = %d\n", n);//以整型的方式 - 读取
	//n = 1,091,567,616
	printf("*p = %f\n", *p);//以浮点型的方式 - 读取
	//*p = 9.0

	return 0;
}

共勉 !

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值