一.memcpy
了解一个函数,从参数开始。观察官方给出的memcpy函数定义,参数一个一个来看,void* destination是目的地,是copy拷贝的目的地地址,是将内容拷贝到此处,而后const void* source是源头,const修饰保证源头不被修改保证安全性,拷贝的内容就从这个地址开始,当然拷贝不可能是无限制的,而后的size_t类型的num就是拷贝的字节个数,返回类型void*返回的目的地地址,便于使用者使用拷贝后的内容。
随后就是实际运用该函数了,在使用该函数前应包含头文件<string.h>,该函数以字节为单位进行拷贝,如果我们要拷贝4个int整形,那么就需要拷贝16的字节(一个int类型4个字节)于是我们可以如下使用。
知道了用法后,可以尝试进行自己实现该函数功能,创建my_memcpy函数来加深自己的理解。实现该函数的关键在于找出一个字节的内容进行拷贝,那么什么类型是一个字节的呢?没错,char类型,于是将void*强制转化为char*再解引用就能实现一个字节的拷贝了。实现如下。
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);//检验指针是否为空,需要包含头文件<assert.h>
void* ret = dest;//返回目的地地址
while (num--)//循环执行num次,即拷贝num个字节
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
memcpy函数固然好用,但存在一个缺陷,该函数在destination和source有任何重叠的时候可能无法生效,于是我们就要使用加强版——memmove
二.memmove
可以看见,memmove和memcpy在参数上是一模一样的,这里不在过多赘述。比较一下相同的数组arr1和arr2在拷贝20个字节的情况下有何不同?可以看见memcpy似乎是对同一个数组一个一个字节顺序进行拷贝,需要拷贝重叠区段arr1[2]时使用的是改变后的值,而memmove似乎拷贝的是改变前数组的值,难道memmove的实现原理是复制了一个相同数组再进行拷贝?
其实也许没这么麻烦,如以上的情况,转换一下思路,从后往前拷贝不就能避免这种错误了吗?不过一直从后往前拷贝就能彻底解决重叠区段的问题了吗?反问自己,想问题要全面仔细,作者思考了以下两种情况:
从图中就算一个一个来试,也能很容易试出,得出以下结论:1.dest在src之前,从前往后拷贝。2.dest在src之后 ,从后往前拷贝。如此便能实现在重复区段下的拷贝,实现库函数memmove的效果。自己实现的代码如下:
void* my_memmove(void* dest,const void* src,size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest > src)//dest在src前
{
while (num--)
{
*((char*)dest + num ) = *((char*)src + num );
}
}
else//dest在src后
{
while (num--)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
return ret;
}
三.memset
memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。注意是以字节为单位,可参数中是int类型的value的的值,因此只能取value后的8位(1字节)为有效值进行设置。当然,我们也可以直接使用一字节的字符类型进行设置,如下:
int main()
{
char arr[] = "Hello world";
memset(arr, 'A', 5);
printf("%s\n", arr);
return 0;
}
//输出结果就是“AAAAA world”