目录
一、memcpy内存拷贝函数
注意事项
二、memcpy与strcpy对比
三、模拟实现memcpy函数
四、memcpy函数不能进行两块存在内存重叠的空间的内存拷贝
五、改进my_memcpy函数
一、memcpy内存拷贝函数
头文件:string.h
函数原型:void* memcpy(void* destination , const void* source , size_t num)
函数作用:将源地址中num个字节的内容拷贝到目标地址中
参数分析:
void *是不指定具体类型指针,意味着该函数可以拷贝任意类型的数据
destination是目标地址,即将源地址的内容拷贝到目标地址中
source是源地址,为目标地址提供拷贝内容
num是拷贝多少个字节
实例代码1:两个数组空间的拷贝
char arr1[] = { 5,4,3,2,1 };
char arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr2, arr1, sizeof(arr1[0]) * 5);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
实例代码2:destination和source不一定是数组,任意可读写的地址空间即可
char arr[20] = "abcdefg";
char* p = "123456789";
memcpy(arr + 2, p + 5, sizeof(char) * 4);
printf("%s\n", arr);
注意事项:
1.拷贝时destination地址的空间需要足够大,至少大于等于num个字节
2.如果destination地址空间存在数据,将会被新数据覆盖
3.memcpy不能进行有内存重叠的两个地址的内存拷贝
二、memcpy与strcpy对比
memcpy是内存拷贝函数,strcpy是字符串拷贝函数
strcpy函数原型:char *strcpy(char *str1, const char *str2)
strcpy函数作用:将字符串str2中的内容拷贝到字符串str1中
对比memcpy函数:
1.memcpy函数逐字节拷贝,strcpy函数遍历str2时遇到\0即停止拷贝,并将\0也拷贝到str1中
2.memcpy函数可以拷贝任意类型数据,strcpy函数只能拷贝字符串
三、模拟实现memcpy函数
注意:优先级:后置++ > 强制类型转换,所以destination和source的强制类型转换需要加括号
void* my_memcpy(void* destination, const void* source, size_t num)
{
if (destination == NULL || source == NULL)
{
return NULL;
}
for (int i = 0; i < num; i++)
{
*(char*)destination = *(char*)source;
((char*)destination)++;
((char*)source)++;
}
}
实例代码:
char arr[] = "123456789";
memcpy(arr, arr + 5, 3);
printf("%s\n", arr);//678456789
四、memcpy函数不能进行两块存在内存重叠的空间的内存拷贝
VS改进后的memcpy函数可以进行内存重叠空间的拷贝:
C语言标准规定,memcpy函数不能进行两块有内存重叠的的空间的内存拷贝,但是在VS编译器下实际测试时,这是由于VS对memcpy函数进行了改进,使得其可以进行内存重叠的空间的拷贝。
char arr[] = "123456789";
memcpy(arr + 2, arr, 5);//121234589
printf("%s\n", arr);
模拟实现的my_memcpy函数不能进行内存重叠空间的拷贝:
但是当使用模拟实现的my_memcpy函数进行拷贝时,结果不尽人意……
结果并非预期的121234589,而是121212189
char arr[] = "123456789";
my_memcpy(arr + 2, arr, 5);//121234589
printf("%s\n", arr);
原因分析:
这是因为在进行内存重叠的两块空间拷贝时,会发生未拷贝的被已拷贝的数据覆盖
例如:将源空间的12345,拷贝到目标空间的34567
当1、2拷贝到3、4的位置时,数组变为121256789,源空间需要拷贝的3、4被1、2覆盖,无法进行拷贝,只能再将1、2拷贝到目标空间,显然这是错误的
五、改进my_memcpy函数
解决上述问题,需要改进的my_memcpy函数的算法
将拷贝的类型分为两类:1.源空间在目标空间前 2.目标空间在源空间前
1.源空间在目标空间前
如下图,常规方法从前向后拷贝(1~3,2~4,……),需要改进为从后向前拷贝(5~7,4~6,……),这样被覆盖的数据已经拷贝完了 ,不影响后续的拷贝
2.目标空间在源空间前
如下图,需要从前向后拷贝(3~1,4~2,……)
总体原则:第一次拷贝的空间不能覆盖源空间
改进后的my_memcpy函数:
void* my_memcpy(void* destination, const void* source, size_t num)
{
if (destination == NULL || source == NULL)
{
return NULL;
}
if (source < destination)//从后向前拷贝
{
for (int i = num - 1; i >= 0; i--)
{
*((char*)destination + i) = *((char*)source + i);
}
}
else//从前向后拷贝
{
for (int i = 0; i < num; i++)
{
*(char*)destination = *(char*)source;
((char*)destination)++;
((char*)source)++;
}
}
}
测试代码:
char arr[] = "123456789";
my_memcpy(arr + 2, arr, 5);//121234589
printf("%s\n", arr);