目录
一.模拟实现memcpy
1.基本介绍
1.1函数原型
1.2功能
由src指针指向地址为起始地址的连续num个字节复制到以dest指针指向地址为起始地址的空间内.
1.3头文件
memcpy函数是包含在string.h库里的。
1.4返回值
memcpy函数的返回值是void*类型,指向dest的首地址。
2.说明
1.srouce指针和destination指针所指向的地址不能重叠,函数返回的是指向destination首地址的指针。如果想复制重叠地址的字符串,应该选择用memmove函数。
2.和strcpy函数不同的是,memcpy函数遇到src中的\0并不会停止复制,而是一定要复制完n个字节的字符.
3.strcpy提供了字符串的复制,即strcpy只能用于字符串的复制,并且strcpu会复制字符串末尾的\0.
4.memcpy提供了一般内存的复制,相对于strcpy,memcpy对复制的内容并没有限制。
5.因为memcpy是一个字节一个字节的进行复制的,所以在对整型数组或者其他元素字节不为1的数组进行复制时,传参时要传sizeof(元素类型)*要复制的长度。例如对整形数组就要传sizeof(int)*size。
3.memcpy的使用
将arr1字符串复制到arr2字符串中:
int main()
{
char arr1[] = "hello world";
char arr2[20];
memcpy(arr2, arr1, strlen(arr1));
arr2[strlen(arr1)] = '\0'; //将arr2末尾字符置为结束符\0
printf("%s\n", arr2);
return 0;
}
//输出结果
hello world
将arr1的第6个字符开始往后的5个字符复制到arr2中:
int main()
{
char arr1[] = "hello world";
char arr2[20];
memcpy(arr2, arr1+6, 5);
arr2[5] = '\0';
printf("%s\n", arr2);
return 0;
}
//输出结果
world
覆盖arr1中的部分数据:
int main()
{
char arr1[] = "hello world";
memcpy(arr1, "xxxxx", 5);
printf("%s\n", arr1);
return 0;
}
//输出结果
xxxxx world
4.模拟memcpy
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src); //确保dest和src不为空指针
char* ret = (char*)dest;// 记录dest的首地址
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
char arr1[20] = "hello world";
char arr2[] = "------";
my_memcpy(arr1, arr2, strlen(arr2);
printf("%s", arr1);
return 0;
}
//输出结果
----- world
二.模拟实现memmove
1.基本介绍
1.1函数原型
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
char* ret = (char*)dest;
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
1.2功能
将num个字节数的字符从src指向的位置复制到dest指向的内存块中。复制就像使用了中间缓冲区一样,允许dest和src重叠。
1.3头文件
memmove函数包含在string.h库中
1.4返回值
memmove函数返回的是void*类型的指针,指向dest的首地址。
2.说明
2.1 和memcpy函数相同,memmove对复制内容没有限制。
2.2 和memcpy函数相同,memmove遇见src中的\0并不会停止复制,而是复制完num个字节数的数据后才停止。
2.3 为了避免溢出,要确保被复制的数组空间足够。
2.4 相对于memcpy函数,memmove能够对重叠空间的内容进行复制。因而可以理解为memmove函数是memcpy函数的加强版。
3.使用memmove
大部分和memcpy函数相同,这里我们只介绍对重叠空间内容的复制。
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
//输出结果
memmove can be very very useful.
4.模拟memmove
4.1分析:
不重叠的时候 跟memcpy函数是类似的。我们只讨论重叠的时候。
第一种情况:当dest指针所指向的地址在src指针所指向的地址的左边时。
这时候只需要将src所指向的元素从前向后依次复制到dest指向的空间里。每复制一次dest和src都向后挪动一格,直到复制了num个元素停止。
第二种情况:当dest指针所指向的地址在src指针所指向的地址的右边时。
我能想到的只有两种解法:
一是再创建一个数组;二是换一种复制的顺序。
第一种方法因为不知道创建数组需要的空间大小,太小放不下,太大内存浪费 。所以第一种不可取。(VS2019不支持动态数组)。
第二种可以从后向前复制,这样就可以在src所指向的元素被覆盖前就把元素复制过去。
4.2代码解析
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src); //防止dest和src为空指针
char* ret = (char*)dest; //记录dest数组的首地址
if (dest < src) //第一种情况
{
while (num--)
{
*(char*)dest = *(char*)src; //因为dest 和src均为无类型指针,所以不能直接解引用
dest = (char*)dest + 1; //同样空指针不能进行算术计算,先将dest转换成char*类型
//的指针,然后因为对无类型指针强制类型转换只是暂时的,所
src = (char*)src + 1; //以左边依然是无类型指针,可以接收任意类型的指针。
}
}
else //第二种情况
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
my_memmove(arr1 + 3, arr1, 3);
printf("%s", arr1);
return 0;
}
//输出结果
abcabc
以上就是我们对memcpy函数和memmove函数的使用和模拟实现啦。