memcpy函数:
函数用途: 将一个指针指向的内存拷贝至另外一个指针指向的内容.
函数原型: void* memcpy(void* destination, const void* source, size_t num);
void*是为了让这个函数可以拷贝所有类型的指针对应的内存而不是某种特定指针, num是拷贝的字节数.
代码演示:
#include <stdio.h> #include <string.h> int main() { int arr1[20] = { 0 }; int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; memcpy(arr1, arr2, sizeof(arr2)); // 将arr2复制至arr1. for (int i = 0; i < 10; ++i) printf("%d%c", arr1[i], " \n"[i == 9]); return 0; }
运行截图:
自己模拟实现memcpy函数:
#include <stdio.h> #include <string.h> void* mymemcpy(void* destination, const void* source, int num) { void* res = destination; while (num--) { *((char*)destination) = *((char*)source); destination = (char*)destination + 1; source = (char*)source + 1; } return res; } int main() { int arr1[20] = { 0 }; int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; mymemcpy(arr1, arr2, sizeof(arr2)); for (int i = 0; i < 10; ++i) printf("%d%c", arr1[i], " \n"[i == 9]); return 0; }
原理就是强转换成char*指针, 一个一个字节的复制拷贝过去, 最后返回拷贝完的指针.
注意:不同编译器下的memcpy函数实现可能不同, 存在有编译器无法支持该函数拷贝自己的某个片段至自己的某个片段.
如下:
#include <stdio.h> #include <string.h> void* mymemcpy(void* destination, const void* source, int num) { void* res = destination; while (num--) { *((char*)destination) = *((char*)source); destination = (char*)destination + 1; source = (char*)source + 1; } return res; } int main() { int arr1[20] = { 0 }; int arr2[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; mymemcpy(arr2 + 2, arr2, sizeof(int) * 5); for (int i = 0; i < 10; ++i) printf("%d%c", arr2[i], " \n"[i == 9]); return 0; }
有些编译器能显示出正确答案: 1 2 1 2 3 4 5 8 9 10.
但是也有编译器显示出如下答案:
这是因为第三位元素开始拷贝本数组, 第一次改完变成1 2 1 4 5 6......, 第二次变成1 2 1 2 5 6..., 第三次发现原来的3已经被拷贝变成1了, 这样的拷贝导致数据被覆盖, 无法访问到之前没被覆盖到的数据, 所以会出现1 2 1 2 1 2 1 8 9 10的情况, 所以memcpy函数不推荐用于自身拷贝自身, 如果要使用建议使用memmove函数.
memmove函数:
作用与memcpy函数一样, 但是可以成功地实现自身拷贝自身的操作.
原理模拟实现:
#include <stdio.h> void* mymemmove(void* destination, const void* source, int num) { void* res = destination; if (destination < source) { while (num--) { *((char*)destination) = *((char*)source); destination = (char*)destination + 1; source = (char*)source + 1; } } else { while (num--) { *((char*)destination + num) = *((char*)source + num); } } return res; } int main() { int arr1[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; mymemmove(arr1, arr1 + 2, 20); for (int i = 0; i < 10; ++i) printf("%d%c", arr1[i], " \n"[i == 9]); return 0; }
原理是比较地址谁大谁小来决定从前向后复制还是从后向前复制. 当待被复制的字符串在小地址处选择从前往后复制, 这样不会有覆盖的问题, 当待被复制的字符串的大地址处则选择从后往前复制.
具体可以自行画图理解.