目录
一、内存函数
二、memcpy
2.1 memcpy的介绍及使用
2.2memcpy函数的模拟实现
三、memmove
3.1 memmove的介绍及使用
3.2 memmove函数的模拟实现
四、memcmp
4.1memcmp的介绍及使用
4.2 memcmp函数的模拟实现
五、memset
5.1 memset的介绍及使用
5.2 memset函数的模拟实现
内存函数与字符串函数大有区别,首先字符串函数仅限于字符串之间的使用,而内存函数可以对任意类型使用,因为不管你传入什么类型的数组,它都是用void*来接收,其次字符串函数关注字符串后面的'\0',而内存函数不关注末尾的'\0',只关注要拷贝或者传入的字节数。
常见内存函数有memcpy/memmove/memcmp/memset 下面就由小编带着大家对这些内存函数做更深入的了解,以及模拟实现吧!
参数介绍:在库函数中,memcpy的参数有三个,分别是目标数组的地址,源数组的地址(被拷贝数组),这两个参数都是使用void*类型的指针来接收,因为void* 的指针可以接收任何类型的指针。最后一个参数就是要操作的字节数,或者说要访问的字节数。该函数的返回值是一个void*的指针,指向目标数组的首地址。
功能介绍:该函数要实现从src这个位置开始,向后复制count个字节大小的数据到dest的内存位置中去,该函数遇到'\0'并不会停下来。
代码使用:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memcpy(arr2, arr1, 20);//从arr1中拷贝20个字节大小的数据到arr2中
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
注意:①因为源数组(被拷贝的数组)不能改变,所以我们用const修饰,起保护作用 ②void 类型不能直进行解引用操作或者++运算,所以在使用之前我们需要进行强制类型转换,又因为这里我们是逐字节操作,所以我们需要将这两个指针强制转换成char*类型来进行操作,这样就可以实现我们想要的效果
③在拷贝过程中,我们的dest的指向会发生变化,所以在最开始,我们创建一个临时的指针变量来接收一下,方便最后返回
④在刚进入函数的时候,我们需要用assert断言一下,防止传入的是空指针
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
void* my_memcpy(void* dest,const void* src,size_t num)//源头数组不被改变,const修饰
//传过来的不会为负数,所以类型为size_t
{
assert(dest && src);
void* ret = dest;
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[20] = { 0 };
my_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
但是memcpy不支持自身内部拷贝,当我们对同一块空间(存在覆盖)的数组进行操作时,会达不到我们想要的结果。重叠的内村拷贝要使用memmove函数来实现。
memmove和memcpy的参数和返回值一模一样,所要达到的效果和memcpy也一模一样,它比meecpy要更好一下,相当于优化,也就是当目标空间和源空间出现重叠的时候,就需要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
memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
memmove模拟实现的时候,我们应该注意,因为目标空间和源空间可能出现重叠的情况,所以我们要分情况来讨论,
情况一:dest
情况二:dest>src的时候,我们需要从后向前拷贝
情况三:dest和src指向的数组无重叠的情况,从前向后以及从后向前都可以
如上三种情况我们可以简化为两种情况,如下图
具体代码如下所示
void* my_memmove(void* dest, void* src, size_t num)
{
//断言
assert(dest && src);
void* ret = dest;
if (dest > src)//如果目标地址大于被拷贝(源头)地址,从后向前拷贝
{
while (num--)
{
*((char*)dest+num) = *((char*)src+num);
}
}
else//如果目标地址小于等于被拷贝(源头)地址,从前向后拷贝
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
return ret;
}
参数介绍:memcmp和memcpy的参数也是一样的,区别就是 返回值不一样,该函数返回值为int,具体如下图所示
功能实现:比较两个内存块,将ptr1所指向的内存块的前num个字节与ptr2指向的前num字节数进行比较。(注意:是逐字节比较)
代码使用:
int main()
{
int arr1[] = { 1,2,3,4 };
int arr2[] = { 1,2,3,5 };
int ret=memcmp(arr1, arr2,16);
printf("%d", ret);
return 0;
}
具体代码如下:
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
//断言
assert(ptr1 && ptr2);
while (num--&&*(char*)ptr1==*(char*)ptr2)
{
ptr1 = (char*)ptr1 + 1;
ptr2 = (char*)ptr2 + 1;
}
return (*(char*)ptr1-*(char*)ptr2);
}
int main()
{
int arr1[] = { 1,2,3,4 };
int arr2[] = { 1,2,3,5 };
//int ret=memcmp(arr1, arr2,16);
int ret = my_memcmp(arr1, arr2, 20);
if (ret == 0)
printf("等于\n");
else if (ret < 0)
printf("小于\n");
else
printf("等于\n");
//printf("%d\n", ret);
return 0;
}
参数介绍:第一个是void*的指针,第二个是int类型的,第三个是无符号类型的整数,返回值是void*类型
功能实现:填充内存块,也就是设置内存,也就是把dest指向的前count字节的内容,设置成'c'的值,注意:以字节为单位来设置,而不是个数。最后返回dest指向的空间地址
代码使用:
int main()
{
char arr1[] = "hello csdn";
memset(arr1+1, 'x', 4);//
printf("%s\n", arr1);
return 0;
}
代码如下:
void* my_memset(void* dest, int c, size_t count)
{
assert(dest);
void* ret = dest;//记住初始位置
while (count--)
{
*(char*)dest = c; //赋值
dest = (char*)dest + 1; //向后移动
}
return ret;
}
到这里,我们今天要介绍的几个常见的内存函数就介绍完了,小编这里建议你看完之后再去动手实际操作一下,搞清楚这些内存函数的原理。希望今天这篇文章对你起到一定的帮助。如果觉得小编写的还可以的,可以一键三连(点赞,关注,收藏)哦,你们的支持是对小编极大的鼓励。谢谢。