1. memcpy
1.1 memcpy的介绍
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
1.2 memcpy的使用
用代码举例:
int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[8] = { 0 }; //把arr1中的前5个数据拷贝到arr2中 memcpy(arr2, arr1, 20);//strcpy不能用,它只针对字符串拷贝,而上面的是整型数据 return 0; }
试试浮点型看看可不可以:
int main() { float arr1[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; float arr2[8] = { 0 }; //把arr1中的前5个数据拷贝到arr2中 memcpy(arr2, arr1, 12); return 0; }
从中发现memcpy它并不在乎整型还是浮点型,所以叫他内存拷贝
void * memcpy ( void * destination, const void * source, size_t num );
在分析一下上面的信息:
void* – 通用类型的指针,可以接受任意类型数据的地址,但是这种指针不能直接解引用和加减运算!
memcpy函数的设计者,不知道未来程序员使用memcpy拷贝什么类型的数据!
size_t num 表示拷贝多少个字节
1.3 模拟实现memcpy库函数
//memcpy函数返回的是目标空间的起始地址 #include <assert.h> void* my_memcpy(void* dest, const void* src, size_t num) { void* ret = dest; assert(dest && src); while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[8] = { 0 }; //把arr1中的前5个数据拷贝到arr2中 my_memcpy(arr2, arr1, 20); return 0; }
调试监视结果如下:
1.4 我想在1,2后面打印1,2,3,4,5会怎么样?
#include <assert.h> void* my_memcpy(void* dest, const void* src, size_t num) { void* ret = dest; assert(dest && src); while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; // 你先打印 1 2 1 2 3 4 5 8 9 10 // 结果却是 1 2 1 2 1 2 1 8 9 10 my_memcpy(arr1 + 2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } }
红色框框:目标空间
绿色框框:想要拷贝的原数据
结论:
所以我们发现:在内存重叠的时候,使用memcpy可能会出现意想不到的结果
建议在内存重叠的情况,使用memmove函数.
2. memmove
2.1 memmove的介绍
void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
2.2 memmove的使用
int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; // 你先打印 1 2 1 2 3 4 5 8 9 10 // 结果却是 1 2 1 2 3 4 5 8 9 10 //说明没有问题 memmove(arr1 + 2, arr1, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } }
代码结果:
2.3 模拟实现memmove库函数
红色框框:目标空间
蓝色框框:想要拷贝的原数据
当dest在src前面,也就是dest的地址更低,src的地址更高的时候
整个图片概念图:
从而有两种方案,综合比较,B方案效果更好
B方案图片解释:
代码样子:
if (dest < src) { //前->后 } else { //后->前 }
完整版代码:
//memcpy函数返回的是目标空间的起始地址 #include <assert.h> void* my_memmove(void* dest, const void* src, size_t num) { void* ret = dest; assert(dest && src); 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; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; // 1 2 1 2 3 4 5 8 9 10 my_memmove(arr1 + 2, arr1, 20); //my_memmove(arr1, arr1+2, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } }
总结:
C语言:memcpy拷贝不重叠的内存
重叠的就交给memmove
memmove > memcpy 100 60
VS:100 100