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

  1. 数据类型详细介绍
  2. 整型在内存中的存储,原码,反码,补码
  3. 大小端字节序介绍及判断
  4. 浮点型在内存中的存储解析

c语言类型

内置类型

  1. char 字符数据类型
  2. short 短整型
  3. int 整型
  4. long 长整型
  5. long long更长的整型
  6. float 单精度浮点数
  7. double 双精度浮点数

自定义类型(构造类型)


以及他们所占存储空间的大小,类型的意义,

1.使用这个类型开辟存储空间的大小,(大小决定了使用范围)

  1. 如何看待内存空间的视角

类型的基本归类

整型家族:属于内置类型

char
unsigned char
signed char
short
unsigned char
signed short[int]
int
unsigned int
signed int
long
unsigned long[int]
signed long[int]
浮点型家族
float
double

构造类型:自定义类型

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

指针类型:大小都是4/8个字节

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

空类型

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

整型在内存中的存储

一个变量的创建是要在内存中开辟空间的,空间的大小是
根据不同的类型而决定的

原码反码补码

计算机中的整型有符号数有三种表示方法,即原码,反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示正,用1表示负
三种表示方法各不相同
无符号数原码反码补码都是相同的
对于整型数据类说:数据存放在内存中其实存放二进制序列的补码

在计算机系统中,数值一律用补码来表示和存储,原因在于,使用补码,可以将符号位和数值域统一处理,加法和减法也可以统一处理(cpu只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路

为什么cpu只有加法器呢,要使用补码存储

int main()
{
    
    
	1 - 1;
	我们cpu用1+-100000000000000000000000000000001
	10000000000000000000000000000001
	10000000000000000000000000000010用原码加完是-2是错误的
	所以要用补码加在一起
	00000000000000000000000000000001   1的补码
	11111111111111111111111111111111   -1的补码
	00000000000000000000000000000000   结果是0
	return 0;
}

//总结:

1.有符号数
正数:原码,反码,补码相同
负数:原码,反码,补码不同需要计算
2.无符号数
原码,反码,补码相同

int main()
{
    
    
	int a = 20;
	00000000000000000000000000010100
	转换成16进制就是0x00000014
	那么为什么在计算机中存储的是14 00 00 00return 0;
}

那么为什么在计算机中存储的是14 00 00 00呢

大小端介绍

大端(存储模式),另外一个名字大端字节序存储模式
是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
小端(存储模式),另外一个名字小端字节序存储模式
是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中

0x 11 22 33 44 11是高位 44是低位
描述的是字节的顺序11是一个字节22是一个字节33和44一样
低地址 高地址
ox11223344 其中11就是高地址44就是低地址
在内存中存储 大端是11 22 33 44
在内存中存储 小端是44 33 22 11
同样在内存中左边是低地址,右边是高地址

指针类型的意义

1.指针类型决定了指针解引用操作符能访问几个字节:charp;p访问了1个字节,intp;p 访问4个字节
2.指针类型决定了指针+1,-1,加的或者减的是几个字节;char
p;p+1,跳过一个字符,int
p;p+1,跳过一个整型-4个字节

面试题

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器字节序

int check_sys()
{
    
    
	int a = 1;
	char *p = (char*)&a;
	if (*p == 1)
	{
    
    
		return 1;
	}
	else
	{
    
    
		return 0;
	}
}
int main()
{
    
    
	//写一段代码告诉我们当前机器字节序是什么
	//返回1,小端
	//返回0,大端
	int ret = check_sys();
	if (ret == 1)
	{
    
    
		printf("小端\n");
	}
	else
	{
    
    
		printf("大端\n");
	}
	return 0;
}

笔试题看下面代码

int main()
{
    
    
	char a = -1;
	// -1
	//10000000 00000000 00000000 00000001 -原码
	//11111111 11111111 11111111 11111110 -反码
	//11111111 11111111 11111111 11111111 -补码
	/*
		因为a只能存8位
	//11111111
	//因为是char所以发生整型提升
	//原符号是有符号的char高位就是符号位
	//11111111 11111111 11111111 11111111 -补码
	//所以是-1
	*/
	signed char b = -1;
	//b只能存8位
	//signed有符号的所以也是-1
	//11111111
	unsigned char c = -1;
	//c只能存8位
	//11111111
	//unsigned无符号的
	//所以整型提升高位不是符号位,高位补0
	//000000000000000000000000011111111-补码
	//正数原码反码和补码都相等
	//所以结果是255
	printf("a=%d,b=%d,c=%d",a,b,c);//-1,-1,255
	return 0;
}

笔试题


int main()
{
    
    
	char a = -128;
	10000000 00000000 00000000 10000000
	11111111 11111111 11111111 01111111
	11111111 11111111 11111111 10000000 
	10000000
	因为char是有符号的所以然后发生整型提升
	11111111 11111111 11111111 10000000 -补码

	本来要算原码,因为是要按照无符号数字打印
	所以是原码补码反码都相同
	11111111 11111111 11111111 10000000
	上面数字的二进制转化为10进制4,294,967,168
	printf("%u\n", a);///4,294,967,168
	%d - 打印十进制的有符号数字
	%u - 打印十进制的无符号数字
	/*return 0;
}*/

%d - 打印十进制的有符号数字
%u - 打印十进制的无符号数字

char的取值范围

1
2

有符号的char的取值范围是-128~127

无符号的char的取值范围是0-255

笔试题

3

int main()
{
    
    
	char a = 128;
	printf("%u\n", a);
	//无符号数-128~127
	//所以这里的128其实就是-128
	//然后再根据上面一样计算
	//10000000000000000000000010000000
	//11111111111111111111111101111111
	//11111111111111111111111110000000
	//11111111 11111111 11111111 10000000
	return 0;
}

笔试题

//笔试题
int main()
{
    
    
	int i = -20;
	//10000000 00000000 00000000 00010100 -原码
	//11111111 11111111 11111111 11101011 -反码
	//11111111 11111111 11111111 11101100 -补码     
	unsigned int j = 10;
	//00000000 00000000 00000000 00001010 -补码
	//11111111 11111111 11111111 11110110 -加的补码
	//11111111 11111111 11111111 11110101 -反码
	//10000000 00000000 00000000 00001010
	printf("%d\n", i + j); //结果是-10
	//按照补码的形式进行运算,最后格式化为有符号整数
	return 0;
}

笔试题

笔试题
笔试题
int main()
{
    
    
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
    
    
		printf("%u\n", i);
	}
	/*
		这里因为是无符号的数,所以是死循环、
      无论咋样变,都是正数
	*/
	return 0;
}

笔试题

int main()
{
    
    
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
    
    
		a[i] = -1 - i;
		//-1,-2,-3,-128,127,126,3,2,1,0
		//因为是字符串,所以只能存放-128-127之间的数字
	}
	printf("%d", strlen(a));
	/*
		-1,-128,127,1,0
		strlen计算就要找\0之前的也就是128+127=255个数字
	*/
	return 0;

笔试题

unsigned char i = 0;
int main()
{
    
    
	for (i = 0; i <= 255; i++)
	{
    
    
		printf("HelloWorld\n");
	}
	//无符号数存放范围0-255
	//条件永远成立,所以死循环
	//255+1 就变成了0;
	return 0;
}

浮点型在内存中的存储

常见的浮点数
3.14159
1E10
浮点数家族包括:float,double,long double类型
浮点数表示的范围:float.h中定义float.h是头文件

int main()
{
    
    
	int n = 9;
	float *pFloat = (float *)&n;
	printf("n的值为:%d\n", n);             //答案是9
	printf("*pFloat的值为:%f\n", *pFloat); //答案是:0.000000

	*pFloat = 9.0;
	printf("num的值为%d\n", n);				//num的值为1091567616					
	printf("*pFloat的值为:%f\n", *pFloat); //9.000000
	return 0;

4
5
6
7

整形存储必须要用整型来存储和取出
浮点型存储必须要用浮点型存储和取出
为什么浮点数和整数的解读结果会差别这么大,浮点数在计算机内部的表示方法
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数v可以表示成下面的形式
/*
(-1)^S * M * 2 ^ E
(-1)^S表示符号位,当s=0,V为正数;当s=1,V为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位
/
/

举例 9.0
1001
(-1)^0 * 1.001 * 2^3
(-1) ^s * M * 2^E
s - 0
M - 1.001
E - 3
/
/float f = 5.5;/
5.5
101.1
(-1)^0 * 1.011
2^2
S = 0
M =1.011
E = 2
在内存中存储这些值
最高位是0 E是2+127=129 二进制10000001 1.011前面的1不存只存011
float类型m是23个所以01100000000000000000000
所以结果是 0 10000001 01100000000000000000000
转为16进制就是0x40b00000

取出来(-1^0) * 1.011 * 2^2

}

int main()
{
    
    
	int n = 9;
	//9的补码是
	//00000000000000000000000000001001
	float *pFloat = (float *)&n;
	printf("n的值为:%d\n", n);             //答案是9
	printf("*pFloat的值为:%f\n", *pFloat); //答案是:0.000000
	//0 00000000 00000000000000000001001
	//还原回来之后上面那样写
	//然后 (-1)^0 * 0.00000000000000000001001*2^-126
	//表示无限接近0的数字所以就是0.000000
	*pFloat = 9.0;
	//1001.0
	//1.001*2^3
	//(-1)^0 * 1.001 * 2^3
	//0 3+127的二进制是10000010 001要补成20个0
	// 0 10000010 00100000000000000000000
	//因为是按照整数打印,所以上面符号位0所以原反补一样
	//结果就是上面数字转化为十进制的数字 1,091,567,616
	printf("num的值为%d\n", n);				//num的值为1091567616					
	printf("*pFloat的值为:%f\n", *pFloat); //9.000000
	return 0;

Guess you like

Origin blog.csdn.net/weixin_52495715/article/details/120739761