memcpy函数
memcpy——内存拷贝(负责不重叠的内存拷贝)
函数定义:
void* memcpy(void* destination,const void* source,size_t num);
//从source的位置开始复制num个字节个数到destination指向的内存中
//num代表要拷贝的字节数
//返回的是detination的起始地址
- memcpy的使用示例如下:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10];
int num = 0;
printf("请输入要拷贝的个数\n");
scanf_s("%d", &num);
memcpy(arr2, arr1 + 2, sizeof(int) * num);//arr1+2表示我要从3开始拷贝5个数
for (int i = 0;i < num;i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
memcpy(arr2, arr1 + 5, sizeof(int) * num);//arr + 5表示我要从6开始拷贝5个数
for (int i = 0;i < num;i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
输出的结果是:
3 4 5 6 7
6 7 8 9 10
- memcpy的模拟实现
因为是模拟实现,所以对函数的定义也是一样的:
void* my_memcpy(void* destination,const void* source,size_t num);
先把主函数的代码写下来:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr1[10];
my_memcpy(arr1, arr, 4*num);
//将3 4 5 6 7 拷贝到arr1中
for (int i = 0;i < num;i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
接下来就是函数模拟实现的部分:
现在我们调用了my_memcpy函数,两个泛型指针接收了我们传过去的arr1和arr,还有num接收了我们传过去的字节数20。我们知道泛型指针是不能进行解引用操作和不能进行加减运算的,而且在拷贝的过程中我们要通过遍历完我们传过去的字节数才能完成对数字的完整拷贝,所以我们需要将dest和src这两个指针强制转换成(char)类型的指针,这要才能达到我们想要的效果。*
下面这个图片可帮助大家更好的理解:
调用函数代码的部分如下:
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);//在使用指针之前先判断一下指针是否为空指针
char* ret = (char*)dest;//先将dest的起始地址保存起来,返回值返回ret即可
while (num)
{
*((char*)dest) = *((char*)src);//字节的拷贝
dest = (char*)dest + 1;
src = (char*)src + 1;
num--;
}
return ret;
}
memmove函数
memmove——内存移动(负责重叠内存的拷贝)
函数定义:
void* memmove(void* destination,const void* source,size_t num);
//跟memcpy函数其实是类似的
什么是重叠内存的拷贝?可以试着用上面的my_memcpy函数自己拷贝自己:
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
char* ret = (char*)dest;
while (num)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
num--;
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int num = 0;
my_memcpy(arr+2, arr, 20);//arr拷贝arr
for (int i = 0;i < 10;i++)
{
printf("%d ", arr[i]);
}
return 0;
}
输出的结果是:
1 2 1 2 1 2 1 8 9 10
预期结果:
1 2 1 2 3 4 5 8 9 10
原因:
我们可以看到蓝色框和红色框之间有重叠的部分,要拷贝的数被已经被拷贝过的数覆盖了,原要拷贝的数已经被替换了,这就是重叠导致出来的现象,不能达到我们所预期的效果。
而memmove函数能解决这种重叠导致的现象,它的使用如下:
输出的结果是正确的.
那么如何对memmove函数进行模拟实现呢,对该函数进行模拟实现,就是在memcpy函数模拟实现的基础上对代码进行修改,解决数字重叠的问题.
思路:
1. 当dest < src时,按正常的流程,从前往后进行对数字的拷贝(memcpy函数的模拟实现就是从前往后拷贝的)
2. 当dest >= src时,从后往前进行对数字的拷贝
以src为分界,地址比src小就从前开始拷贝,比src大或者等于src就从后开始拷贝,这样就可以避免数字被覆盖的现象了
模拟实现的代码如下:
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest,void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src)
{
while (num)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
num--;
}
}
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
#include <string.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
size_t sz = sizeof(arr) / sizeof(arr[0]);
my_memmove(arr+2, arr, 20);
for (int i = 0;i < sz;i++)
{
printf("%d ", arr[i]);//输出结果:1 2 1 2 3 4 5 8 9 10
}
return 0;
}
综上我们可以知道memcpy函数是有局限性的,如果想要对内存进行拷贝,可以直接使用memmove函数,在vs中memcpy函数是可以解决重叠现象的,但在其他的编译器里就不一定可以解决了。