内存函数的介绍及模拟实现
今天的这篇博客主要是向大家介绍内存函数以及如何模拟实现内存函数。内存函数,顾名思义就是操作内存的函数,也是非常常用的一类函数,主要包括memcpy、memmove、memcmp和memset。首先,我们来学习memcpy。
1.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
对于memcpy函数,我们需要注意一下几点:
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 '\0' 的时候并不会停下来。
代码示例:
#include <stdio.h> #include <string.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; memcpy(arr2, arr1, 20); //memcpy - 内存拷贝 for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }
模拟实现memcpy函数 :
#include <stdio.h> #include <string.h> #include <assert.h> void* my_memcpy(const void* dest, const void* source, size_t num) { void* ret = dest; assert(dest && source); while (num--) { *(char*)dest = *(char*)source; dest = (char*)dest + 1; source = (char*)source + 1; } return ret; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; //memcpy - 内存拷贝 //模拟实现memcpy函数 my_memcpy(arr2, arr1, 40); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }
注意事项: 因为dest和source都是无类型指针,不知道解引用访问几个字节,也不知道加一跳过几个字节,所以将它们都强制类型转化为char*,一个字节一个字节来交换。
如果我们想调用自己定义的my_memcpy函数来将数组的数据拷贝到数组的另一个位置上,这样可不可以呢?现在我们来尝试一下。
代码示例:
#include <stdio.h> #include <string.h> #include <assert.h> void* my_memcpy(const void* dest, const void* source, size_t num) { void* ret = dest; assert(dest && source); while (num--) { *(char*)dest = *(char*)source; dest = (char*)dest + 1; source = (char*)source + 1; } return ret; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; //memcpy - 内存拷贝 //模拟实现memcpy函数 my_memcpy(arr1+2, arr1, 20); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
输出结果:
代码分析:
我们可以看到,用我们自己定义的my_memcpy函数不能完成这个任务。那么我们用库函数memcpy能不能完成这个任务呢?我们现在来试一试。
代码示例 :
int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; //memcpy - 内存拷贝 memcpy(arr1+2, arr1, 20); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
输出结果:
可以看到,用memcpy函数出色地完成了我们的任务。那为什么会这样呢?
代码分析:
对于memcpy函数,只要实现了不重叠拷贝就可以了。但是在VS中的memcpy函数既可以实现不重叠拷贝,也可以实现重叠拷贝!!!相当于你只要求一个学生考60分,但是结果他给你考了个100分。不过,memcpy函数在其他编译器就有可能实现不了重叠拷贝。
想要实现重叠拷贝,就要借助另外一个内存函数了,就是memmove函数。
2.memmove
void * memmove ( void * destination, const void * source, size_t num );
对于memmove函数,我们需要注意一下几点:
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
代码示例:
#include <stdio.h> #include <string.h> int main() { //memmove函数可以处理内存重叠的情况 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; memmove(arr, arr+2, 20); for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
我们可以看到,memmove函数将3 4 5 6 7移动到1 2 3 4 5的位置上了。其实学会使用memmove函数并不难,真的有难度的是如何去模拟实现memmove函数。
在模拟实现memmove函数之前,我们先来分析一下。
了解了模拟实现memmove函数的基本思路,现在我们一起来模拟实现memmove函数。
模拟实现memmove函数:
#include <stdio.h> #include <string.h> void* my_memmove(void* dest, const void* source, size_t num) { //可以把原数据-从前往后拷贝,也可以从后向前拷贝 //dest的地址高于source的地址时,先把数据拷给高地址,再把数据拷给低地址(从后往前拷贝) //dest的地址低于source的地址时,先把数据拷给低地址,再把数据拷给高地址(从前往后拷贝) assert(dest && source); void* ret = dest; if (dest < source) { //第一种情况:从前向后拷贝 while (num--) { *(char*)dest = *(char*)source; dest = (char*)dest + 1; source = (char*)source + 1; } } else { //第二种情况:从后向前拷贝 while (num--)//注意这时num的值已经减了一 { *((char*)dest + num) = *((char*)source + num); } } return ret; } int main() { //memmove函数可以处理内存重叠的情况 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr, arr+2, 20); for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
3.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
对于memcmp函数,我们需要注意的是:memcmp函数比较数据大小是一个字节一个字节的数据来比较的,比较num个字节的数据。
代码示例:
#include <stdio.h> #include <string.h> int main() { float arr1[] = { 1.0,2.0,3.0,4.0 }; float arr2[] = { 1.0,3.0 }; int ret = memcmp(arr1, arr2, 8); printf("%d\n", ret); return 0; }
模拟实现memcmp函数:
//memcmp - 内存比较 #include <stdio.h> #include <assert.h> #include <string.h> int my_memcmp(const void* ptr1, const void* ptr2, size_t num) { while (*(char*)ptr1 == *(char*)ptr2) { ptr1 = (char*)ptr1 + 1; ptr2 = (char*)ptr2 + 1; num--; if (num == 0) { return 0; } } return (*(char*)ptr1 - *(char*)ptr2); //注意:不相等时,不一定返回值为1或者-1 } int main() { float arr1[] = { 1.0,2.0,3.0,4.0 }; float arr2[] = { 1.0,2.0 }; int ret = my_memcmp(arr1, arr2, 8); printf("%d\n", ret); return 0; }
#include <stdio.h> #include <assert.h> #include <string.h> int my_memcmp(const void* arr1, const void* arr2, size_t num) { assert(arr1 && arr2); while (num--) { if (*(char*)arr1 != *(char*)arr2) { return *(char*)arr1 - *(char*)arr2; } arr1 = (char*)arr1 + 1; arr2 = (char*)arr2 + 1; } return 0; } int main() { int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 int arr2[] = { 1,2,3,0,0 };//01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 //int ret = memcmp(arr1, arr2, 13); int ret = my_memcmp(arr1, arr2, 10); printf("%d\n", ret); return 0; }
4.memset
void * memset ( void * ptr, int value, size_t num );
对于memset函数,我们需要注意的是:memset函数是将一个字节的数据改为value,并不是直接将一个整型或者一个浮点数直接该成value。
代码示例:
#include <stdio.h> #include <string.h> int main() { int arr[10] = { 0 }; memset(arr, 1, 20);//以字节为单位设置内存 for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } }
代码分析:
模拟实现memset函数:
#include <stdio.h> #include <assert.h> void* my_memset(void* ptr, int value, size_t num) { assert(ptr); void* ret = ptr; while (num--) { *(char*)ptr = value; ptr = (char*)ptr + 1; } return ret; } #include <stdio.h> #include <string.h> int main() { int arr[10] = { 0 }; my_memset(arr, 1, 20);//以字节为单位设置内存 for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } }
以上就是这篇博客的全部内容,主要介绍了memcpy、memmove、memcmp和memset四个内存函数以及模拟实现这四个内存函数。大家如果觉得有收获的话,可以点个赞支持一下!