数据在内存中的存储


一、整形在内存中的存储

首先先要了解原码、反码和补码。
原码:直接将二进制按正负数的形式翻译成二进制就可以。
反码:将原码的符号位不变,其他位依次按位取反即可。
补码:反码加一就得到补码,正数的原、反补码都相同。
对于整形来说:数据存放内存中其实存放的是补码。
在这里插入图片描述
VS的debug模式就会把局部变量后面填充一些0xcc。
在这里插入图片描述
但是我们会发现顺序有点不对劲,这是为什么呢?

二、大小端介绍

什么是大端小端:
大端(存储模式):是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。
网络传输的字节序固定使用大端。
设计一个小程序来判断当前机器的字节序:
代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
int check_sys() {
	int i = 1;
	return(*(char*)&i);
}
int main() {
	int ret = check_sys();
	if (ret == 1) {
		printf("小端\n");
	}
	else {
		printf("大端\n");
	}
	system("pause");
	return 0;
}

练习1:

#include<stdio.h>
#include<stdlib.h>
int main() {
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d", a, b, c);
	system("pause");
	return 0;
}

在这里插入图片描述
把char强转为int时,前面高位的三个字节,填充的都是符号位,char和signed char都是有符号的,所以直接补一,unsigned char是无符号的,所以高位补零。
结果:
在这里插入图片描述
练习2:

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

%u是打印unsigned int(无符号十进制的整数)。
char的表示范围:-128->127
在这里插入图片描述
int->unsigned int这个转换过程中,数据的二进制表示在内存不发生任何变化。
char自身是有符号的,高位是一,所以高位全补一。所以结果很大。
在这里插入图片描述
练习3:

#include<stdio.h>
#include<stdlib.h>
int main() {
	char a = 128;
	printf("%u\n", a);
	system("pause");
	return 0;
}

char得到不了+128,给127(0111 1111)+1的话得到1000 0000,其实已经溢出,得到的是-128。所以结果与-128相同。
(char会溢出,int也会溢出,只要你这个类型是有上限的,都会溢出,这是非常常见的)
python里面的int默认是4个字节,但是如果计算过程中发现溢出了,会自动扩容。只要内存足够,就能表示足够大的数字。
练习4:

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

触发隐式类型转换,int转unsigned int
在这里插入图片描述
练习5:

#include<stdio.h>
#include<stdlib.h>
int main() {
	unsigned int i = 0;
	for (i = 9; i >= 0; i--) {
		printf("%u\n", i);
	}
	system("pause");
	return 0;
}

unsigned int 没有小于零的情况,所以i>=0这个条件写了和没写一样。
在这里插入图片描述
unsigned 类型是特别容易溢出的,原则就是,能不用就不用。Java、Python根本就没有unsigned。
练习6:

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

\0是ASCII值为零的那个字符,(a[i]=-1-i)int赋值给char会出现截断的情况。
在这里插入图片描述
所以i为255的时候,-1-255就是‘\0’.所以下标为255的位置被设为了‘\0’,此时求字符串长度就是255。
练习7:

#include<stdio.h>
#include<stdlib.h>
int main() {
	short num = 32767;
	short int a = num + 1;
	printf("%d\n", a);
	system("pause");
	return 0;
}

在这里插入图片描述
练习8:

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

i=255再加一会溢出
在这里插入图片描述
所以这个程序是个死循环。


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

IEEE754标准描述了浮点数在内存中如何存储。
1.float
一个浮点数在计算机里,是用“科学计数法”的方式来表示的,只不过不是10的几次方,而是2的几次方。以二为底,算二的E次方。
在这里插入图片描述
S是符号位,浮点数默认是有符号的。
2.double
在这里插入图片描述
E越大,能表示的数据范围就越大,M越大,能表示的数据精度就越高。
因此实践中还是优先考虑使用double这个类型。
浮点数存储的这个标准,不是C语言标准规定的,其他编程语言也遵守。
重点来啦:浮点数去表示一些特殊的数字的时候才是精确的,很多时候是不能精确表示的。就会导致两个浮点数直接进行比较相等,可能就会出现问题。
例如:

#include<stdio.h>
#include<stdlib.h>
int main() {
	double a = 1.6;
	double b = 0.3;
	double c = a + b;
	double d = 1.9;
	if (c == d)
		printf("相等\n");
	else
		printf("不相等\n");
	system("pause");
	return 0;
}

在这里插入图片描述
a:
在这里插入图片描述
b:
在这里插入图片描述
计算机按照IEEE754标准来表示浮点数时,很多数字不能精确表示。所以在使用浮点数时,不能直接比较,如果必要比较相等,可以设立误差。(把两个待比较的数字做差,判定差值是否在一个允许的误差范围之内)
例如:

#include<stdio.h>
#include<stdlib.h>
int main() {
	double a = 1.6;
	double b = 0.3;
	double c = a + b;
	double d = 1.9;
	if (c-d<0.001&&c-d>-0.001)//需要手动指定一个允许的误差范围
		printf("相等\n");
	else
		printf("不相等\n");
	system("pause");
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dhdhdhdhg

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

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

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

打赏作者

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

抵扣说明:

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

余额充值