目录
前言:
之前,我们了解到的字符操作函数应该是最为常见的,比如strcmp,strcpy等函数。但是,这些似乎都有个缺点,只能对字符进行操作,是不是太单一了,而现在我要介绍内存操作函数,是以字节为单位进行操作的。而且函数原型里面的形参都是void类型,也就是说什么类型均可接受,我们来一起看看吧!
一、memcpy函数的模拟实现
首先,这个内存操作函数和strcpy函数很像,只不过一个是操作内存的。我们来看一下这个函数的原型:
void* memcpy(void* dest, const void* src, size_t count)
这里的size_t在64位环境上的话代表了long long unsigned int ,在非64位环境下是long unsigned int。
实际上操作的话如下:
int main()
{
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int b[4] = { 5, 6, 1, 2 };
memcpy(a, b, 16);// 5 6 1 2 5 6 7 8 9 10
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
在memcpy传参过程中,a就表示要改数组的首位置,b表示改动数组的首位置,16表示16个字节,也就是说,传的是字节,上述程序中是为了将5 6 1 2传过去,而一个int类型的数据是4个字节,所以就是4 * 4 = 16。
现在重头戏来了:如何模拟实现呢?
既然是一字节一字节修改,我们只需要一个字节一个字节修改即可,从前往后的方式,将void*转化为char*即可,有了思路便可以写出这样的模拟实现的代码:
void* my_memcpy(void* dest, const void* src, size_t count)
{
//首先进行断言:
assert(dest && src);//存储首位置地址,方便之后好返回
void* set = dest;while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return set;
}
这样便可以实现我们的模拟memcpy函数的功能了。
二、memmove的模拟实现:
memmove函数比较特殊,相当于是对memcpy函数的补充。
比如在之前第一段程序里面,如果是传参:(a + 6, a + 5, 16),你以为是1 2 3 4 5 6 6 7 8 9吗?实际上是:1 2 3 4 5 6 6 6 6。究其原因就是这里其实发生了内存重叠,前往后传会把后面的给替换掉,因此出现了错误。
所以,这里就需要重新实现:
先看这个函数的原型:
void* memmove(void* dest, const void*src, size_t count)
与之前的函数原型一致,就表明了,我们要区分传进去的地址是要从前往后传还是从后往前传。
这个很简单,就只需要判断地址谁大谁小即可,所以:
void* my_memmove(void* dest, const void* src, size_t count)
{
assert(dest && src);
char* set = dest;
//后往前
if (src < dest)
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
//前往后
else
{
while (count--)
{
*((char*)dest) = *((char*)src);
src = (char*)src + 1;
dest = (char*)dest + 1;
}
}
return set;
}
完美实现!nice!
继续加油!