C语言内存函数
memcpy的使用和模拟实现
作用:针对内存块进行拷贝
声明:
void * memcpy ( void * destination, const void * source, size_t num );
destination 待粘贴内存块地址
source 复制内存块地址
num 决定更改多大内存,单位字节
从 source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存空间
(遇到 \0 不会停止)
头文件:string.h
memcpy 的使用:

memcpy 的模拟实现:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* p1, const void* p2, size_t num)
{
assert(p1 && p2);
void* s1 = p1; // 尽量不对传参值进行修改
const void* s2 = p2;
while (num--)
{
*(char*)s1 = *(char*)s2;
// 第一类指针偏移(推荐) // 第二类指针偏移
s1 = (char*)s1 + 1; // ((char*)s1)+1;
s2 = (char*)s2 + 1; // ((char*)s2)+1;
}
return p1;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 8,8,8,8,8 };
my_memcpy(arr1 + 2, arr2, 20);
for (int i = 0; i < 10; i++)
printf("%d ", arr1[i]);
return 0;
}
当 source 和destination 内存有任何的重叠时,复制的结果不保证
例如:
cpp
int arr[] = {1,2,3,4,5,6,7,8,9,10};
memcpy(arr+2,arr,20);

当你尝试模拟实现的 emecpy 函数整流程走一变时
会发现样本空间指向3时,已经被修改为了1
所以导致最后打印结果为:
1 2 1 2 1 2 1 8 9 10
不是理想的
1 2 1 2 3 4 5 8 9 10
当想打印具有重叠内存的空间时用 ememove 函数
memmove 的使用和模拟实现
声明:和memcpy一样
void * memcpy ( void * destination, const void * source, size_t num );
destination 待粘贴内存块地址
source 复制内存块地址
num 决定更改多大内存,单位字节
使用方式也一样,区别在于 memmove 多了个处理重叠内存的功能
memmove 的模拟实现:
回到上一个问题如何解决?
1.在替换前复制整个模版内存一次
这个方式可以解决,但是有个更为巧妙的方式
当你的指针由后向前开始替换时会发现,在打印时不会将样本空间覆盖掉
但是情况反转呢?

会发现由后向前替换会出现问题
但由前向后,问题就会解决
我现在发现如果空间出现重叠现象,只会有
上图两种情况,和一种完全重叠情况
但空间完全重叠和 空间不重叠 两种替换方式都能解决
所以我们只需分两类情况
1.样本空间在被修改空间后方
重叠区域在样本空间前方
举个例子:现在有 2 瓶冰红茶,一瓶快过期了,一瓶时间还长着
一般是先将快过期的喝掉,再喝时间还长的
这个样本空间也一样,先用空间重叠的后用未重叠的
所以为右前向后替换
2.样本空间在被修改空间前
重叠空间在样本空间后放
所以由后向前替换
现在替换方式对于什么情况确定了,还需要确定一个什么条件判断一个什么情况
由于指针一直处于空间的最左侧,所以我们可以利用指针的大小确定情况
而且,数组在空间中由低向高存放
所以:
1.样本空间在被修改空间后方(由前向后)
样本空间指针打印被修改空间指针
p2 > p1
2.样本空间在被修改空间前方(由后向前)
样本空间指针小于被修改空间
p2 < p1

代码如下:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* p1, const void* p2, size_t num)
{
assert(p1 && p2);
void* s1 = p1;
const void* s2 = p2;
if (p2 > p1)
{
while (num--)
{
*(char*)s1 = *(char*)s2;
s1 = (char*)s1 + 1;
s2 = (char*)s2 + 1;
}
}
else
{
s1 = (char*)s1 + num - 1; // 解决有后向前,指针最开始在后方
s2 = (char*)s2 + num - 1;
while (num--)
{
*(char*)s1 = *(char*)s2;
s1 = (char*)s1 - 1;
s2 = (char*)s2 - 1;
}
}
return p1;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1, arr1 + 2, 20);
for (int i = 0; i < 10; i++)
printf("%d ", arr1[i]);
printf("\n");
int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr2+2, arr2, 20);
for (int i = 0; i < 10; i++)
printf("%d ", arr2[i]);
return 0;
}

memset 的使用
声明:
void * memset ( void * ptr, int value, size_t num );
ptr 修改空间的地址
int 需要修改成的内容
num 需要修改的空间,大小为字节
memset 的使用:

memcmp 的使用
声明:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比较从ptr1和ptr2指针指向的位置开始,向后的num个字节
和 strcmp 类似只不过这个比较的是内存中的内容(区别不大)
memcmp 的使用:

区别在于memcmp可以比较任意类型