目录
前言:
1 . 介绍 memmove函数
2 . 模拟 memmove函数
2 . 1 . 简易模拟(不考虑覆盖拷贝)
2 . 2 . 模拟分析(考虑覆盖拷贝)
2 . 2 . 1 覆盖拷贝所在的问题
2 . 2 . 2 覆盖拷贝所在的问题
2 . 2 . 3 覆盖拷贝的书写
2 . 3 . 模拟书写(考虑覆盖拷贝)
2 . 3 . 模拟细节(考虑覆盖拷贝)
2 . 3 . 全模拟代码(考虑覆盖拷贝)
2 . 3 . 全模拟代码举例(考虑覆盖拷贝)
我可以通过学习的难易顺序来分,可以说 strcpy函数 是最简单的复制(拷贝)函数,但是其只能运用于字符串,随后就是 memcpy函数 ,其实基于内存上的复制(拷贝)函数,相较于 strcpy函数 不会具有同样的局限性,但是 memcpy函数也是有其的巨大缺陷,其不能对本身进行覆盖拷贝,于是便有了 memmove函数 ,其是能够对本身进行覆盖拷贝的函数,其又同时兼备了 memcpy函数 可做的事。(注:保留 memcpy函数 是因为保证用memcpy函数进行书写的代码的顺利通过性,所以即使 memmove函数 玩玩全全强于 memcpy函数 也是不能将其删去,于是也会有这样的两个函数,但是在有些编译器下,也将 memcpy函数 实现成为与 memmove函数 同样的功能(例如:vs2019)。)
对本身进行覆盖拷贝:
#include
#include
void print(int* arr,int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 1, arr + 3, 20);
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
printf("\n");
return 0;
}
函数原型:void *memmove(void *dest, const void *source, size_t count)
返回值说明:返回指向dest的void *指针
参数说明:dest,src分别为目标串和源串的首地址。count为要移动的字节的个数
函数说明:memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
首先,创建这个函数的作者是无法考虑到如今我们需要怎么样的类型进行拷贝,于是,同样的我们就需要用到 void* 类型的指针,来进行函数传参的接收。
此处我们需要注意:
#include
#include
//memmove函数的模拟
void* my_memmove(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
//数组的打印
void print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memmove(arr1, arr2, 20);//memmove函数的模拟
int sz = sizeof(arr1) / sizeof(arr1[0]);
print(arr1, sz);//数组的打印
printf("\n");
return 0;
}
此处,我们就要重点注意覆盖拷贝的问题,因为会导致未被拷贝的数值已招到更改。以图为例:
就以之前所模拟(简易模拟(不考虑覆盖拷贝))实验就可以发现,只需将:
就可以得到:
本人想到的就只有:
方法一:会有一个严重的问题,根本不知道需要开辟多大的空间(本人使用vs2019)。小了,会出现程序错误;大了,会导致空间浪费。所以在此看来,这样的不行的。
方法二:在针对不同的情形下,只要考虑完全,这就是很完美的选择,同时也不会浪费空间。
我们所知晓的覆盖错误就是因为,未进行拷贝就被更改,那我们就想办法,在其未被修改前进行拷贝。
情况一:src在dest之前。
我们可以发现自src下标小端拷贝,就不会出现之前的未进行拷贝就被更改的情况。(逆顺序)
情况二:dest在src之前。
我们可以发现自src下标大端拷贝,就不会出现之前的未进行拷贝就被更改的情况。(顺顺序)
而在未出现覆盖的情况,怎么样的顺序的拷贝都是可以实现的。于是,就可以正式开始书写代码了。
经过之前的分析,因为未被覆盖的类型,任何顺序都是可以的。于是,为了书写代码的简洁,我们将 src < dest 全分为逆顺序, src > dest 全分为顺顺序。(数组是随着下标的增长,地址随之变大)
src < dest :
//逆顺序
while (count--)
{
*((char*)dest+count) = *((char*)src + count);
}
src < dest :
//顺顺序
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
void* my_memmove(void* dest, const void* src, int count)
{
assert(dest && src);
void* ret = dest;
if (src > dest)
{
//顺顺序
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//逆顺序
while (count--)
{
*((char*)dest+count) = *((char*)src + count);
}
}
return ret;
}
#include
#include
//memmove函数模拟
void* my_memmove(void* dest, const void* src, int count)
{
assert(dest && src);
void* ret = dest;
if (src > dest)
{
//顺顺序
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//逆顺序
while (count--)
{
*((char*)dest+count) = *((char*)src + count);
}
}
return ret;
}
//数组的打印
void print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 3, arr + 1, 20);
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);//数组的打印
printf("\n");
return 0;
}