前言
作者:小蜗牛向前冲
名言:我可以接收失败,但我不能接收放弃
如果觉的博主的文章还不错的话,还请 点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。
这次主要为大家分析内储操作函数的使用。
memcpy内存拷贝函数
该函数主要用来拷贝各类型的数据。
参数
我们要传给该函数的参数有:
dest:指向要在其中复制内容的目标数组的指针,类型转换为 void* 类型的指针。
src:指向要复制的数据源的指针,类型转换为 const void* 类型的指针。
num:要复制的字节数,size_t是无符号整数类型。
头文件
#include <string.h>
下面进行代码演示:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[10] = { 0 }; memcpy(arr2, arr1, sizeof(arr1)); return 0; }
从上面代码我们可以看出,拷贝整形成功,那么mencpy到底是如何拷贝的呢?为什么strcpy函数就仅仅只能拷贝字符串,而memcpy却能够拷贝所有的内存数据呢?
首先,我可以告诉大家,memcpy是对内存中的数据进行一个一个字节进行拷贝的。
其次,strcpy的拷贝方式是让数组中的字符直接经行交换,所以这样整形,浮点型,结构体都不可以进行拷贝。
那么,由于mencpy函数是一个一个字节进行拷贝的,而所有的内存单元都是由字节组成,内存的最小单位是1个字节,所以当mencpy函数进行一个一个字节进行拷贝,能够拷贝所有的内存单元。
基本上面对mencpy函数内存拷贝方式的理解,下面我们进行该函数实现的模拟。
memcpy函数的模拟实现
void* my_memcpy(void* dest, const void* src, size_t num) { assert(dest && src);//断言 char* start =(char*)dest;//标记目标数组的地址 //一个一个字节进行拷贝 while (num--) { *(char*)dest = *(char*)src; ++(char*)dest; ++(char*)src; } return start; }
当我们实现完memcpy函数,这个函数真的能够拷贝所有的内存数据吗?
下面继续看:
void* my_memcpy(void* dest, const void* src, size_t num) { assert(dest && src);//断言 char* start =(char*)dest;//标记目标数组的地址 //一个一个字节进行拷贝 while (num--) { *(char*)dest = *(char*)src; ++(char*)dest; ++(char*)src; } return start; } int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10}; //int arr2[10] = { 0 }; my_memcpy(arr1+3, arr1, 20); return 0; }
本来按理来说arr1拷贝完的结果为{1,2,3,1,2,3,4,5,9,10};但实际结果是:
为什么会出现这种状况呢?
这是和我们的memcpy的实现方法有关,我们是从前向后拷贝的,但是这样就会造成一个问题,当源内存块和目标内存块是重叠时,我们在拷贝前面的内存时后面的内存也会改变,这样就会使得拷贝失败。专门写了用来拷贝源内存块和目标内存块是重叠时这种情形的函数memmove。
memmove函数
其实我们从函数的定义是看,memmove和memcpy都是相同的,但不同的是memmove函数可以处理源内存块和目标内存块是重叠的情形。
参数
二者参数都是相似的,这里就不在多说,下面我们要讨论一下,源内存块和目标内存块是重叠的不同情形。
情形1(dest)
我们都是一个一个字节拷贝的,但怎么才能实现内存拷贝呢?,如果是情形1我们只有进行从前-->后拷贝就可实现(memcpy的实现方式)
情形2(dest>src&&dest
如果是情形2如果我们仍然是从前-->后拷贝,这样就会出现数据覆盖的现象,但我们可以从后-->前拷贝就可以避免数据覆盖。
情形3(dest>scr+num)
如果是发现情形3的情形,既然目标空间都和内存空间都不重叠了,那么拷贝的方式无论是从前-->后或者从后-->前都是可以的。
我们理解上面的三种拷贝情况,我们继续举例说明一下memmove函数的功能。
为了更好的理解menmove函数的功能,下面我们模拟实现。
//模拟实现memmove void* my_memmove(void* dest, const void* src, size_t num) { assert(dest && src);//断言 char* start = (char*)dest; if (dest < src) { while (num--) { *(char*)dest = *(char*)src; ++(char*)dest; ++(char*)src; } } else { while (num--) { *((char*)dest + num) = *((char*)src + num); } } return start; }
memcmp内存拷贝函数
我们前面学习了,字符拷贝函数,下面我们来见识一下内存拷贝函数吧!
该函数是用来比较两个内存块
参数
ptr1:
指向内存块的指针。
ptr2:
指向内存块的指针。
num:
要比较的字节数。
返回值
该函数返回一个整数值,指示内存块内容之间的关系:
<0:
在两个内存块中不匹配的第一个字节在 ptr1 中的值低于在 ptr2 中的值
0:
两个内存块的内容相等
>0:
在两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值
代码举例:
int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 1,2,3,4,6 }; int ret = memcmp(arr1, arr2, 20); if (ret > 0) { printf("前20字节数中在两个内存块中不匹配的第一个字节在arr1中的值>arr2中的值\n"); } else if(ret<0) { printf("前20字节数中在两个内存块中不匹配的第一个字节在arr1中的值<arr2中的值\n"); } else { printf("两个内存块的内容相等\n"); } return 0; }
memset内存设置函数
有时候我们需要对内存中值经行修改,就可以用到memset函数。
参数
ptr:
指向要填充的内存块的指针。
value:
要设置的值。该值作为 int 传递,但该函数使用此值的无符号 char 转换来填充内存块。
num:
要设置为该值的字节数。
size_t是无符号整数类型。
返回值
代码举例:
int main() { char mane[20] = "Xiao ming"; memset(mane + 5, '*', 1);//设置内存 printf("%s", mane);//打印 return 0; }
那么我们可以用memset对数组初始化吗?
大家可以看到,我本意(误用)是想把arr的内容都初始化为1,但却最后初始化的值并不是我想要的结果,为什么呢?
原来是我对memset的函数的理解不到位,该函数是一个字节一个字节进行设置的,而不是直接设置一个整形。
所以在数组中设置的第1元素其实是01 01 01 01(十六进制,一个字节=8bit位)。其实用memset初始化数组也是可以,但是比较麻烦,所以还是要慎重使用。
好了就分析这些内存函数,下面对本篇博主的重点进行简单总结。
总结
memcpy函数是用来进行内存拷贝的,但要注意C语言规定:该函数只要能拷贝内存不重叠的内存即可,但在有些编译器中也是可以拷贝内存重叠的内存的。(如VS)
memmove是C语言用来拷贝内存重叠的内存的。
memcmp可以比较两个内存块。
memset函数可能并不一定试用于数组内容的初始化(大家可以动手试试)。
大家喜欢的来个三连支持博主吧!