数据在内存中的储存

文章目录


前言

C语言中有很多种数据类型,本文将具体介绍这些数据到底是如何储存在内存中的,以及这样储存的好处~


一、数据在内存中是如何储存的?

  • 整数在内存中的储存

整数的二进制表示方法有三种——原码,反码,补码(均由符号位和数值位两部分构成)

规律:正整数的原反补均相同,负整数三种各不同

原码:直接将数值按照正负数的形式翻译成二进制

反码:除最高位符号位外将其他位次按位取反

补码:在反码的基础上加1

重要关系:原码——取反+1——>补码(这两者之间可以互相转换)

                        <——、、、——                   

结论:整数直接以补码的形式在内存中储存

原因:由上述的重要关系可得,原码和补码之间的转换是相同的,不需要额外的硬件电路

  • 大小端字节和字节序的判断

1.什么是大小端?

大端储存:将数据的低(高)位字节内容保存在高(低)地址处

小端储存:将数据的低(高)位字节内容保存在低(高)地址处

易知地址的小是从左往右,由低到高,该图中将将数据a的地址按小端储存。

  • 浮点数在内存中的储存

我们可以先做一下下面的联系,想想会打印出什么?

#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;
}

结果如下:我们发现同样的数字,将整型赋值给浮点型和将浮点型赋值给整型的结果均不相同,由此我们可以推断出整型和浮点型在内存中的储存方式不同,那么浮点型是如何储存的呢?

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V   =  (−1) ^S* M * 2^E
•(−1)S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
•M 表⽰有效数字,M是⼤于等于1,⼩于2的
(因为是二进制所以不可能超过2,又要用科学计数法表示所以M>1)
•E 表⽰指数位
举例来说:(类似于科学计数法)
⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2 。
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
IEEE 754规定:

其中我们规定E=0时,E=1-127;E全为1时,如果M=0,则表示无穷大
对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

由上图我们可知为什么会有双精度浮点型和单精度浮点型,因为有64位的双精度浮点型有52位储存有效数字易知其精度要远大于32位

此时我们再自己思考一下上面的练习为什么会有这样的结果。

二、C语言的内存函数

1.memcpy函数

作用:将源函数指定的数据复制到目标函数中

注意:

  • 这个函数在遇到'\0'时不会停下来
  • 如果源函数与目标函数有任意的重叠都是未定义的
  • num是字节数而不是元素的个数
#include <stdio.h>
void* my_memcpy(void* dest, const void* src, size_t num)//只要实现不重叠字符的覆盖就好了
{//void类型的指针不能够直接解引用使用,为了函数的普适性,我们应该一个字节一个字节的复制,so应该强制转化为char*类型
	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 11,12,34,56,78 };
	my_memcpy(arr1, arr2, 20);//可以不接受任何返回值
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);

	return 0;
}
 

如图所示,将arr2中的20个字节所对应的数字复制到了arr1中

2.memmove函数

memmove函数的功能更加强大能够处理重叠部分的复制

由图可知重叠复制与dest和str的位置关系有关,我们只要根据他们的位置关系进行复制即可,不重叠两种方式均可

#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)//传输的num是字节数
{
	assert(dest && src);
	void* ret=dest;
	if (dest > src)//地址也是数字是可以比较的
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);//从前向后复制
		}
	}
	else {
		while (num--)
		{
			*(((char*)dest)++) = *(((char*)src)++);//转化成字符型指针再进行自增
		}
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1, arr1+3, 20);//可以不接受任何返回值
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);

	return 0;
}

总结

数据在内存中的储存虽然基础但相当重要并且颇有学问,本文讲解了有关数据储存更深入的知识,敬请期待下一章的练习!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值