快速复习之——内存函数和数据在内存中的存储
本文介绍了C语言中常用的内存操作函数及其实现原理,包括memcpy、memmove、memset和memcmp。重点分析了这些函数对字节操作的特点,以及模拟实现方法。同时探讨了数据在内存中的存储方式,包括整数的补码表示、大小端字节序判断,以及浮点数按IEEE 754标准的存储格式。通过多个代码示例展示了类型转换、整形提升等概念在实际编程中的应用,并解释了相关输出结果的原因。文章最后还提供了一个关于
内存函数(操作对象是字节)
内存函数 ,操作对象是字节,头文件<string.h>
-
1.memcpy使⽤和模拟实现
source 和 destination 没有任何的重叠,
void * memcpy ( void * destination, const void * source, size_t num )
模拟实现
#include<iostream>
using namespace std;
void*my_memcpy(void*dest,void *scr,int num)
{
assert(dest&&scr);
void*ret=dest;
while (num--)
{
*(char*)dest = *(char*)scr;
dest = (char*)dest + 1;
scr = (char*)scr + 1;
}
return ret;
}
-
2. memmove使⽤和模拟实现
source destination可以重叠
void * memmove ( void * destination, const void * source, size_t num )
模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;
void* my_memmove(void* dest, void* scr, int num)
{
void* ret = dest;
assert(dest && scr);
//从前向后拷贝
if (dest < scr)
{
while (num--)
{
*(char*)dest = *(char*)scr;
dest = (char*)dest + 1;
scr = (char*)scr + 1;
}
}
else //从后向前拷贝
{
while (num--)//num先使用,
{
*((char*)dest + num) = *((char*)scr + num);
}
}
return ret;
}
-
3. memset函数的使⽤
memset函数对内存单元的设置是以字节为单位的
void * memset ( void * ptr, int value, size_t num )
例如

注意,是对字节的修改,例如

memset后

-
4. memcmp函数的使用
int memcmp ( const void * ptr1, const void * ptr2, size_t num );

数据的存储
-
1. 整数在内存中的存储
正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同
对于整形来说:数据存放内存中其实存放的是⼆进制的补码。
-
2. ⼤⼩端字节序和字节序判断
- ⼤端(存储)模式:
- 是 指数据的低位字节内容保存在内存的⾼地址处,
- ⼩端(存储)模式:
- 是 指数据的低位字节内容保存在内存的低地址处,
- vs上是以小端字节序存储

判断大端还是小端
void check()
{
int a = 1;
if (*(char*)&a == 1)//把a的地址转换为char*从而访问一个字节
printf("小端\n");
else
printf("大端\n");
}
练习1
#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;
}
结果;a=-1,b=-1,c=255;
练习2
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
结果;4294967168
分析
#include <stdio.h>
int main()
{
char a = -128;
//-128的原码:10000000 00000000 00000000 10000000
//-128的补码:11111111 11111111 11111111 10000000
//char a- 10000000
//%u的形式打印:(当作无符号的整形,整形提升)
//整形提升
//因为a是char类型,有符号,所以,按照符号提升,补1;
//提升结果 11111111 11111111 11111111 10000000
//按%u的形式输出,
//当作无符号整形,11111111 11111111 11111111 10000000就是原码。
printf("%u\n",a);
return 0;
}
练习3(变式)
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
结果;4294967168
分析
与前面相比,得到的a是一样的。所以,结果一样。
#include <stdio.h>
int main()
{
char a = -128;
//128的原码:00000000 00000000 00000000 10000000
//128的补码:00000000 00000000 00000000 10000000
//char a- 10000000
//%u的形式打印:(当作无符号的整形,整形提升)
//整形提升
//因为a是char类型,有符号,所以,按照符号提升,补1;
//提升结果 11111111 11111111 11111111 10000000
//按%u的形式输出,
//当作无符号整形,11111111 11111111 11111111 10000000就是原码。
printf("%u\n",a);
return 0;
}
练习4
#include <stdio.h>
#include <string.h>
int main()
{
char a[1000];
int i;
for(i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
结果;255
分析
对于char类型,范围-128~127;

然而,对于超出范围的数。例如,-129

练习5
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
结果;死循环
分析;unsigned char 的范围0~255;不可能超过255;
练习6
#include <stdio.h>
//X86环境⼩端字节序
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf("%x, %x", ptr1[-1], *ptr2);
return 0;
}
结果;4, 2000000
分析

知识点
1,%d-是以十进制的形式打印有符号的整数(认为我们要打印的数据在内存中是以有符号数的补码进行存诸的)
2,signed char的取值范围是 -128~127
无符号字符的取值范围是 0~255
3,整体提升
1,有符号整数提升是按照变量的数据类型的符号位来提升的
2、无符号整数提升,高位补0
char类型

-
3. 浮点数在内存中的存储
- 根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
IEEE 754规定:
对于32位的浮点数(float),最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字 M
对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效 数字M

M
前⾯说过, 1 ≤ M < 2 ,也就是说,M可以写成 1.xxxxxx 的形式,默认这个数的第⼀位总是1,因此可以被舍去,
E
⾸先,E为⼀个⽆符号整数(unsignedint) 这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我 们知道,科学计数法中的E是可以出现负数的,所以IEEE754规定,存⼊内存时E的真实值必须再加上 ⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
接下来,我们来看一下9.5在内存中的存储

3.2.2 浮点数取的过程
1.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);
运用上面的知识,来解决下面的难题吧!
题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("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
输出结果;
n的值为:9
*pFloat的值为: 0.000000
n的值为:1091567616
*pFloat的值为:9.000000
解析放评论区咯!
感谢您的阅读,完结,撒花!
更多推荐




所有评论(0)