目录
前言
本篇文章主要介绍四个C语言中常见的内存函数:memcpy,memmove,memset,memcmp。下面来详细地介绍这四个函数,提前说明一点:在使用这些函数之前,需要包含头文件:include<string.h>
一、memcpy函数
1.函数原型
void* memcpy(void* destination,const void* source,size_t num);
1. 参数:(1)destination:指针,指向目标空间,拷贝后的数据存放在这里。
(2)source:指针,指向源空间,要拷贝的数据从这里来,由于这块内存中的数据不发生改变,因此用const修饰。
(3)num:要拷贝的数据所占的字节数。
2. 返回值:返回目标空间的起始地址。
2.功能
memcpy函数完成将源空间中要拷贝的数据拷贝到目标空间中的指定位置,memcpy函数不关注要拷贝的数据的类型。
下面我们通过代码来感受一下memcpy函数的功能
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int str[] = { 4,5,6 };
memcpy(arr, str, 3 * sizeof(str[0]));
size_t sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果

可以看到,通过memcpy函数我们将str指向的数组中的三个数据都拷贝到了arr指向的数组中。
3.模拟实现
void* My_memcpy(void* dst, const void* src, size_t num)
{
void* ret = dst;
assert(dst && src);
while (num--)
{
// 拷贝
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return ret;
}
测试
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int str[] = { 4,5,6 };
int *ret = My_memcpy(arr, str, 3 * sizeof(str[0]));
for (int i = 0; i < 9; i++)
{
printf("%d ", *(ret + i));
}
return 0;
}
运行结果

小思考:如果有这样一段代码
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
memcpy(arr+2, arr, 5 * sizeof(arr[0]));
return 0;
}
也就是我们想将arr数组中的1,2,3,4,5拷贝到(arr+2)指向的位置之后,通过仔细观察,我们发现,当前面的数据拷贝到后面的位置的同时,后面的数据被覆盖了,那当我们想要继续拷贝后面的数据时,数据因为被覆盖掉了,就不能达到我们想要的效果。但是C语言标准库中的memcpy函数已经解决了这个问题,而下面我们要介绍的memmove函数就是专门来应对这种情况的。
二、memmove函数
1.函数原型
void*memmove(void*destination,const void*source,size_t num);
memmove函数的参数,功能都和memcpy函数相同,唯一不同的就是:memmove函数处理的源空间中的内存块和目标空间中的内存块是可以重叠的。
2.功能
下面直接通过代码来感受memmove函数的功能:
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
//拷贝
memmove(arr + 2, arr, 5 * sizeof(arr[0]));
size_t sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果

上面代码成功实现了将1,2,3,4,5拷贝到(arr+2 )指向的位置之后。
3.模拟实现
通过画图我们来分析,要实现memmove函数,就要正确的处理内存块重叠的问题。观察下面的图,我们发现,实际分为三种情况:
(1)源空间中要拷贝的数据的起始地址在目标空间起始地址之后,为了避免将要拷贝的数据覆盖,只要将要拷贝的数据从前到后依次拷贝到目标空间的对应位置处即可。
(2)源空间中要拷贝的数据的起始地址在目标空间之前,为了避免将要拷贝的数覆盖,我们可以将要拷贝的数据从后到前依次拷贝到目标空间中对应的位置处。
(3)源空间内存块与目标空间内存块不重叠,从前到后和从后到前拷贝均可。

通过上面的分析,下面我们来实现代码
void* My_memmove(void* dst, const void* src, size_t num)
{
void* ret = dst;
assert(dst && src);
if (dst > src)
{
while (num--)//从后到前
{
*((char*)dst + num) = *((char*)src + num);//巧妙地应用了num
}
}
else
{
while (num--)//从前到后
{
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
return ret;
}
测试

三、memset函数
1.函数原型
void* memset(void* str,int value,size_t num);
参数:
(1)str:指向目的空间,存放目的空间的起始地址。
(2)value:即要设置的值。函数会把value转化为unsigned char类型的数据来设置,也就是以字节为单位来设置值。也可以直接给memset传一个unsigned char类型的字符,例如:'x','A'...
(3)num:想要在str指向的空间中修改的数据所占的字节数。
2.功能
将指定长度内存的空间中的内容设置为指定的内容,并返回目标空间的起始地址。
下面通过代码演示来感受其作用
int main()
{
char str[] = "Hello World!";
memset(str, 'x', 6);
puts(str);
return 0;
}
输出结果
xxxxxxWorld!
四、memcmp函数
1.函数原型
int memcmp (const void* ptr,const void* str,size_t num);
参数:ptr和str为指针,指向指定的内存块,也即开始比较的的位置;num为从指定位置开始需要向后比较的字节数 。
返回值:当ptr指向的数据大于str指向的数据时,返回大于0的数;
当ptr指向的数据小于str指向的数据时,返回小于0的数;
当ptr指向的数据等于str指向的数据时,返回0。
2.功能
比较从ptr和str指向的位置开始,向后的num个字节。同时,memcmp函数相较于strcmp函数,能够比较的数据类型不仅仅局限于字符串,但是,当在比较字符串大小时,memcmp函数与strncmp函数作用相同。
代码演示01
int main()
{
int arr1[] = { 1 };// 1在内存中为:0x 01 00 00 00
int arr2[] = { 256 };// 256在内存中为:0x 00 10 00 00
int a = memcmp(arr1, arr2, 1);//当只比较一个字节时,arr1>arr2。
if (a > 0)
printf("arr1>arr2\n");
else if (a < 0)
printf("arr1<arr2\n");
else
printf("arr1==arr2");
return 0;
}
输出结果
arr1>arr2
代码演示02
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdgkj";
int x = memcmp(arr1, arr2, 5);
if (x > 0)
printf("arr1>arr2\n");
else if (x < 0)
printf("arr1<arr2\n");
else
printf("arr1==arr2");
}
输出结果
arr1<arr2

1万+

被折叠的 条评论
为什么被折叠?



