首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

求大牛围观,求回答memmove 函数内存覆盖的条件,多谢!

2013-07-08 
求大牛围观,求回答memmove 函数内存覆盖的条件,谢谢!!我在一个博客看到的一个代码,不明白memmove 函数中内

求大牛围观,求回答memmove 函数内存覆盖的条件,谢谢!!
我在一个博客看到的一个代码,不明白memmove 函数中内存覆盖的条件,向大牛请教下!

代码:

void * __cdecl memmove ( void * dst,const void * src,size_t count)

{

         void * ret = dst;

         if (dst <= src || (char *)dst >= ((char *)src + count))

         {

                   // 若dst和src区域没有重叠,则从起始处开始逐一拷贝

                   while (count--)

                   {

                            *(char *)dst = *(char *)src;

                            dst = (char *)dst + 1;

                            src = (char *)src + 1;

                   }

         }

         else

         { // 若dst和src 区域交叉,则从尾部开始向起始位置拷贝,这样可以避免数据冲突

                   dst = (char *)dst + count - 1;

                   src = (char *)src + count - 1;

                   while (count--)

                   {

                            *(char *)dst = *(char *)src;

                            dst = (char *)dst - 1;



                            src = (char *)src - 1;

                   }

         }

         return(ret);

}



我的疑问:
(1)内存重叠应该分两种情况,如下图所示,判断对应的不内存重叠的条件不应该仅仅是 
(dst <= src || (char *)dst >= ((char *)src + count) 吧?
求大牛围观,求回答memmove 函数内存覆盖的条件,多谢!
(2)由于待拷贝区域src指向的字符串是const 类型的,也就是说是不能改变的,但是在内存重叠时,可能会改变源地址的内容啊?
(3)既然从后往前拷贝可以完成该函数的功能,那直接使用从尾部往开始处拷贝不是更方便吗?为什么还要执行从开始处往尾部拷贝呢?
求大牛解释!!
[解决办法]
1. 应该是注释错误, 这种情况不是没有区域有重叠. 而是从前往后拷贝, 覆盖的地方只会是已经读过的内容. 还没有读取的内容不会被覆盖掉的. 所以可以保证正常.
2. const 只是对 C++ 起提示和语法检查作用. 是起不到对内存的保护作用的.
3. 对有些情况, 从后面拷贝就不行了呀. 比如 dst < src, dst + count > src 的时候, 从后面开始拷贝, 第一个字符拷贝过去就会覆盖到 src 前面的字符. 而前面的字符还没读取过, 就有问题了!
[解决办法]
你图中2的情况,从尾部开始拷贝就错误了

图中1的情况,虽然有重叠,但是从头部开始拷贝不会出问题,所以没有加进判断条件
[解决办法]
四种情况:
1:无重叠,两种方法都可以,选择正向复制。
2:dest尾部与src首部重叠,选择正向复制,以免冲掉src中未复制的数据。
3:dest首部与src尾部重叠,选择反向复制,以免冲掉src中未复制的数据。
4:完全重叠,两种方法都可以,选择正向复制(其实最好不复制)

[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:

1. 应该是注释错误, 这种情况不是没有区域有重叠. 而是从前往后拷贝, 覆盖的地方只会是已经读过的内容. 还没有读取的内容不会被覆盖掉的. 所以可以保证正常.
2. const 只是对 C++ 起提示和语法检查作用. 是起不到对内存的保护作用的.


3. 对有些情况, 从后面拷贝就不行了呀. 比如 dst < src, dst + count > src 的时候, 从后面开始拷贝, 第一个字符拷贝过去就会覆盖到 src 前面的字符. 而前面的字符还没读取过, 就有问题了!


谢谢你的回复啊。在问一个问题啊,在内存重叠时,是有可能修改源地址的参数的。如果由于在执行以后的程序时可能会用到源地址的参数,即我传入的源地址参数就是不能改变,那么这里源地址的参数被默默的改变了,此时会不会是一个隐含的问题呢。


它修改的是指针的一份拷贝, 不会修改到你传的时候使用的参数的.
当然, 它可能会修改到你传的参数指向的内存. 但是它对指向的修改是不会返回到你的参数中去的.
就好比你传了一个 int 参数给一个函数, 函数里面修改了这个 int, 外面的值是不会变的.

你看看我这个例子,貌似和你说的不同,是不是我没理解你的意思啊
#include <iostream>
using namespace std;

void* Memmove (void * dst,const void * src,size_t count)

{
//则从起始位置开始向尾部拷贝
void * ret = dst;
while (count--)
{
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return(ret);

}


int main()
{
char src[10] = {'1','2','3','4','5'};
cout<<"Old: "<<src<<endl; //输出12345
Memmove(src + 1,src,5);
cout<<"New: "<<src<<endl;//输出11111,src的内容改变了
return 1;


src 的内容是可能会变呀
不变的是, src 还是代表这个 {'1','2','3','4','5'} 数组的首地址.
我是说, 代码里面的 src = (char *)src + 1; 这种改变不会影响外面的 src.
果然是我理解错了,呵呵不好意思。
再问个问题啊,在内存重叠时,是有可能修改源地址的参数的。如果由于在调用该函数之后可能会用到源地址指向的内存内容,即我传入的源地址内存内容就是不能改变,那么这里源地址的内存内容被默默的改变了,此时会不会是一个隐含的问题呢。。谢谢你的回答!


当然, 你要保证源内容不变, 就用 memcpy 撒. memmove 的名字就表明被移走了, 移走了后原来的内存就不应该期待还会存在撒.

呵呵,谢谢你的耐心啊,呵呵。你说的是用memcpy,但是我在百度百科看的memcpy函数都没有参数检测,而且直接要求是参数不重叠。如果参数内存重叠就不能完成功能。是不是有问题啊?
具体见http://baike.baidu.com/view/736225.htm
再次谢谢你啊。呵呵


对的呀, 你要保证源内容不变, 参数内存又有重叠, 本来就是不可能完成的任务, memcpy 返回失败表示不可能完成正是它该做的.

热点排行