以前发表过关于字符串拷贝函数的实现和分析,那么为什么有了字符串拷贝函数,还需要内存拷贝函数?
一.关于内存拷贝函数的原型和实现。
原型:
void *memmove( void *dest, const void *src, size_t count );
实现:
void* my_memmove(void* p1, void* p2, size_t count)
{
assert(p1);
assert(p2);
char *dest = (char *)p1;
char *src = (char *)p2;
if ((dest > src) && (dest < src + count))
{
while (count--)
{
*(dest + count) = *(src + count);
}
}
else
{
while (count--)
{
*dest = *src;
dest++;
src++;
}
}
return p1;
}
二.内存拷贝函数的意义
1).首先关注函数的参数,void类型指针,告诉我们内存拷贝函数可以接受任意类型。所以就产生一个问题--类型强制转换。为了说明这个问题我们首先看一段程序分析一下。
void *my_memmove(char *dest,const char *src,size_t count)
{
assert(dest);
assert(src);
......
}
上面写的也是内存拷贝函数的一种实现,但是是比较挫的一种实现方式。试着分析一下,这个函数只接收char类型的指针,那么如果要改变的是float型的指针,要怎么办?在传参的时候强制类型转换?那岂不是很麻烦,每当使用这个函数的时候,只要不是char类型的指针都需要强制类型转换。那么,有没有一种一劳永逸的做法?肯定是有,将函数的参数设置成void型,就万事大吉了。只需要在函数实现的内部强制类型转换。
2).内部强制类型转换需要注意的问题
首先应该知道在32位平台上,int型占4字节,float型占4字节,char型占1字节,double型占8字节。那么在函数内部强制类型转换的时候应该转换成什么型呢?
看一个小程序:
void* my_memmove(void* p1, void* p2, size_t count)
{
assert(p1);
assert(p2);
double *dest = (double *)p1;
double *src = (double *)p2;
if ((dest > src) && (dest < src + count))
{
while (count--)
{
*(dest + count) = *(src + count);
}
}
else
{
while (count--)
{
*dest = *src;
dest++;
src++;
}
}
return p1;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int i = 0;
my_memmove(arr + 4, arr + 2, 16);
for (i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
system("pause");
return 0;
}
当把传进来的参数强制转化为double 程序出现奔溃。试着分析一下。
(1).在内存中数组arr是以4个字节存储,但是在内存拷贝的时候是以8个字节为单位拷贝,说的直白一点就是,要把数组中第一个和第二个元素(1和2)拷贝到8个字节中,那么在输出的时候是用四个字节输出的。输出的内容就是
我们会发现输出的并不是我们想要的。我们要的是 1 2 3 4 3 4 5 6 9 10.
(2)那么用强制转换成什么类型最合适?
不难发现,让指针转换成char类型不会出错。原因就不再啰嗦了。
三.程序为什么分为两种情况?
1).一种情况是从后向前拷贝,一种是从前向后拷贝。
2).试着分析
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
my_memmove(arr + 4, arr + 2, 16);
从前向后拷贝的时候,3放在5的位置,4放在6的位置,该拷贝5的时候,5已经变成了3.和我们的初衷不一样,所以引入了从后向前拷贝的情况。
以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。