函数介绍
本章内容给大家展示一些内存操作函数
memcpy
memmove
memset
memcmp
给大家讲解该函数,并实现模拟
memcpy
函数讲解
memcpy函数是C语言中的一个标准库函数,用于在内存之间进行数据复制。它的函数原型如下:
void *memcpy(void *destination, const void *source, size_t num);
memcpy函数的作用是将源内存块中的数据复制到目标内存块中,复制的字节数由num指定。
destination是目标内存块的指针,指向要将数据复制到的位置。
source是源内存块的指针,指向要复制数据的起始位置。
num指定要复制的字节数。
注意,memcpy函数的参数类型为void*,这意味着它可以复制任意类型的数据。
memcpy函数的工作原理是按字节复制。它从源内存块中以字节为单位逐一复制数据,并将其存储到目标内存块中。这就是为什么需要指定要复制的字节数,以确保复制的范围正确。
值得注意的是,memcpy函数不能处理内存重叠的情况。如果源内存块和目标内存块有重叠部分,使用memmove函数会更安全,它可以正确处理这种情况。
接下来我们代码示例,来看一下该函数效果:
int main() { int arr1[10] = { 0 }; int arr2[] = { 32,23,14,22,5 }; memcpy(arr1, arr2, 20); for (int i = 0; i < +5; i++) { printf("%d ", arr1[i]); } return 0; }
这个函数和strcpy的区别在于strcpy只可以拷贝字符串类型,而memcpy函数可以拷贝任何类型的数据
模拟实现
接下来我们来模拟实现一下
void* my_memcpy(void* arr1, const void* arr2, size_t size) { void* ret = arr1; assert(arr1 && arr2); size_t i = 0; while (i < size) { *(char*)arr1 = *(char*)arr2; arr1 = (char*)arr1 + 1; arr2 = (char*)arr2 + 1; i++; } return ret; } int main() { int arr1[10] = { 0 }; int arr2[] = { 32,23,14,22,5 }; my_memcpy(arr1, arr2, sizeof(arr2)); for (int i = 0; i < 5; i++) { printf("%d ", arr1[i]); } return 0; }
接下来,来具体分析一下模拟的memcpy函数,首先他的返回值是指向目标内存的地址,所以我们设置ret来记录其实位置的地址,同时用assert函数来保证传入的arr1指针和arr2指针非空,之后进入我们的复制循环中,由于该函数是一个字节一个字节的访问,所以才循环内部,我们把arr2强转为char类型后解引用,赋值给arr1强转为char 后解引用,在这里我们不能使用
(char)arr1++ = (char)arr2++;
的原因是++的优先级高,所以如果使用的话,arr1就会跳过以传入数据的字节,也就是4个字节,之后才强转为char* 进行操作,并不会一个一个字节的操作,所以我们不使用这个代码,我们直接把arr1强转为char*后进行+1操作在赋值给arr1,同理arr2进行同样的操作。这样就可以一个字节一个字节的进行操作了。
memmove
函数讲解
刚刚在介绍memcpy时我们提到了,memcpy不能处理内存重叠的情况,而memmove可以,那么我们就来介绍一下memmove。
memmove 是 C/C++ 标准库中的一个函数,用于在内存中移动一定数量的字节数据。
memmove 函数的函数原型如下:
void* memmove(void* dest, const void* src, size_t n);
参数解释如下:
dest:目标内存块的指针,表示要移动数据的目标位置。
src:源内存块的指针,表示要从其中复制数据的起始位置。
n:要移动的字节数,即要复制的数据大小。
memmove 函数的功能是将 src 所指向的内存块中的数据复制到 dest 所指向的内存块中,同时保证当 src 和 dest 内存块重叠时也能正常执行。
相比于另一个相关的函数 memcpy,memmove 函数在处理内存块重叠的情况下更为安全,因为它会根据内存块的重叠情况自动选择正确的数据复制方式。这意味着 memmove 函数即使在源和目标内存块重叠的情况下,也可以正确地进行数据复制,而不会导致数据损坏。
介绍完成后我们来看一下该函数的效果。
int main() { int arr1[] = { 1,2,3,4,5,6,7,8 }; memmove(arr1, arr1 + 2, 8); for (int i = 0; i < 8; i++) { printf("%d ", arr1[i]); } return 0; }
模拟实现
那么接下来我们来模拟实现一下该函数
void* my_memmove(void* dest,const void* src, size_t num) { void* ret = dest; assert(dest && src); size_t i = 0; if (dest < src) { while (i < num) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; i++; } } else { while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8 }; my_memmove(arr1+2, arr1, 8); for (int i = 0; i < 8; i++) { printf("%d ", arr1[i]); } return 0; }
对于内存重叠的情况无非就是dest<src和dest>src两种情况,dest<src的情况呢,其实和memcpy差不多,所以在这里我们不再过多赘述,我们只了解一下dest>src的情况,首先如果dest>src的话会出现覆盖的现象,所以我们从后面往前面赋值,直接把dest和src强转为char*然后加上num个字节数,从后面往前面赋值,我们直接把循环条件设置为num–,下次进入while循环直接就是从倒数第一个字节到了倒数第二个字节,实现了一个字节一个字节操作的编程行为。