文章目录
前言
路漫漫其修远兮,吾将上下而求索。
- 顾名思义,内存库函数就是针对内存进行操作的库函数
一、memcpy
1、使用:
void * memcpy ( void * destination , const void * source ,size_t num);
memcpy --> memory 内存 + copy 拷贝 --> 内存拷贝
参数:
- destination: 目标空间的指针
- source :源数据起始位置的指针
- num: 所要拷贝源数据 source 中数据所占内存空间的字节个数
使用:引头文件 <string.h> 或者 <memory .h>
分析:由于是拷贝内存中的数据,不知道其具体类型,所以我们会联想到之前利用冒泡排序的思想来实现qsort 函数中,将内存中的数据一个字节一个字节地交换,所以memcpy 得参数指针类型和返回类型都是 void* ,即泛型指针;
2、模拟实现:
代码如下:
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* tmp = dest;//返回目标空间得起始地址
while (count--)
{
*(char*)dest = *(char*)src;
//调整
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return tmp;
}
int main()
{
//模拟实现memcpy
int arr1[] = { 1,2,3,4,5 };
int arr2[10] = { 0 };
void* tmp = my_memcpy(arr2, arr1, sizeof(arr1));
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
代码输出结果如下:
好奇的你可能还会去尝试利用 memcpy 自己拷贝自己,结果发现……
行不通,理想中得运行结果应该是 1 2 3 1 2 3 4 5 9 10,但是实际得输出结果为 1 2 3 1 2 3 1 2 9 10;为什么呢?
由上图可知,当源数据得末尾被目标空间覆盖的时候,而从前往后打印会使得源数据在操作得过程中而被改变,所以输出结果为 1 2 3 1 2 3 1 2 9 10;
在C语言标准中,mencpy 负责拷贝两个独立空间中的数据,可以不考虑覆盖拷贝得情况,但是memmove 可以实现重叠拷贝。
二、memmove
1、使用
- void * memmove ( void * deststination , const void * source , size_t num);
- memmove --> memory 内存 + move 移动;
参数:
memmove 与 memcpy 的区别是,memmove 函数处理源内存块和目标内存块是可以重叠的;故而所以如果源内存块和目标内存块出现重叠就使用 memmove 函数处理;
2、模拟实现
你可能回想说在实现memmove 时再创建一个数组拷贝一下源数据然后再拷贝就可以了,理论上这个方法是可行的,但是再创建一个数组不太高效并且存在不用创建数组就可以实现重叠拷贝的方法;
在上面我们分析了,my_memcpy 不能实现重叠拷贝的原因,但是认真思考你会发现,源数据的后半部分被目标空间给覆盖了,而我们从前向后拷贝就会先拷贝源数据的前部分数据,而由于目标空间与源数据后部分重叠,所以改变了源数据后段的内容,要是如果我们先拷贝被覆盖的后段呢?即从后向前拷贝视乎就能解决这个问题;
图解如下:
显然,当源数据的后段被目标空间覆盖时,即 src< dest (当两空间相互独立的时候,向前向后拷贝均可);当源数据的前段被覆盖的时,即 src > dest(当两空间相互独立的时候,向前向后拷贝均可);
注:随着数组下标的增长,其地址也变大;
代码如下:
#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* tmp = dest;
if (dest > src)//源数据的后段可能被覆盖--> 先拷贝后段
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
else//否则就是源数据的前段可能被覆盖--> 先拷贝前段
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
return tmp;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
void* tmp = my_memmove(arr + 3, arr, sizeof(int) * 5);
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
代码输出如下:
三、memcpy
memcmp --> memory 内存 + cmpare 比较 --> 内存块比较
在一个字节一个字节中进行数据大小的比较
参数:
例:
调试--> 内存
四、memset
- memset --> memory 内存 + set 设置 --> 内存设置
- 常用来将内存中的值改为0;
- void * memset ( void * ptr , int value , size_t num);
使用的例子如下:
总结
memcpy 内存拷贝--> C语言标准中明确说明memcpy 可以不考虑重叠拷贝
memmove --> 可以实现重叠拷贝
memcmp --> 将内存中的数据一个字节一个字节地比较
memset --> 不用利用循环便可以批量改变内存中的数据