C语言中的内存函数是对内存中数据实现更改操作的一系列函数,本文模拟实现memmove来分享一点对数据进行更改操作的一些较难点,还望各位大佬不吝赐教!
这里以int类型的数组为例,将数组内第5,6,7,8,9个元素向前移动到对应的第1,2,3,4,5个元素的位置并实现覆盖,即最后的数组内容应该是5,6,7,8,9,6,7,8,9,10,11,12,13,14,15。
原始数组 int arr1[15] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
预计更改后 int arr1[15] = { 5,6,7,8,9,6,7,8,9,10,11,12,13,14,15 };
考虑的内存修改应该是能够对所有数据进行操作修改,因此设计函数my_memmove(void*dest,void*src,int byte)
void*表示可以接受任何类型的指针或地址
dest是移动到的目标的首个元素地址,src是你要移动对象的首个元素地址(分别对应上文中arr以及arr+4)
byte表示你要移动数据的字节,因为是int类型要移动5个数据的话应该是20个字节,因此应该传sizeof(int)*5给byte。
my_memmove(arr1+4, arr1, 5 * sizeof(int));
好了接下来是函数具体的实现,先看目前指针的位置
显然只要把src处的元素放到dest处,然后执行dest++和src++再将新的src处元素放到新的dest处,只到5个元素都移动成功即可
考虑到void*类型的指针不能直接解引用,因此先转换为char*类型再进行更改操作。
为什么转换为char*?因为char*类型的指针加1只移动一个字节,可以较好的操作其他类型数据的内存。
这样一来上述修改内存和指针移动只需进行byte次(byte为你要移动的数据所占的内存)
void my_memmove(void* dest, void* src, int byte)
{
for (; byte > 0; byte--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
最后用for循环打印数组内容
完了吗?没完,按照上述方法只能让dest指针在src指针左边或重合的情况完成预期任务,若src在dest左边就会出错,将arr1和arr1+4交换位置
my_memmove(arr1+4, arr1, 5 * sizeof(int));
理论上数组内容应该是1,2,3,4,1,2,3,4,5,10,11,12,13,14,15
实际上是1,2,3,4,1,2,3,4,1,10,11,12,13,14,15
图解一下
好了第五次移动即将出问题
没错,理论上此刻dest部分应该从9修改为5,但是实际上确实9修改为1
这是因为此刻src指向的元素不是原始数组中的5,而是被修改成为了1
因此造成了修改错误
所以,面对src在dest左边的情况下我们有必要使用另一种方法来移动数据
我们可以从后开始移起,就是让可能提前被覆盖的数据先移,这样避免了出错。
因此这样就得到了最终函数的代码
void my_memmove(void* dest, void* src, int byte)
{
if(src>=dest)
for (; byte > 0; byte--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
else
for (;byte>0;byte--)
{
*((char*)dest + byte-1) = *((char*)src + byte-1);
}
}
图解
需要注意的是byte自减4次才表现为上图指针移动1格(因为char*类型指针移动4次等于int*类型指针移动1次)
进行byte次操作即可实现数据移动