其实这个问题大致的意思就是让你写一个函数,这个函数有三个参数:需要移动的指针地址void *src,目的地地址void*dest,以及内存的字节长度len。让你将src中的内容移动到dest中。
之所以总结这个,是因为在面试腾讯的实习时,两次被问到这个问题,在一面的时候面试官挺耐心的,因为我没听过这个(虽然很基础),他就很细心地讲解,然后让我写出自己的思路;在二面的时候另一个面试官让我把代码写出来,结果我写得很复杂,就跪了。。。
其实在一面之后,我有回去百度看了下这个函数,但是因为自己知道了在内存移动的时候会出现什么情况,就没看代码实现(自大啊。。。),后来就吃亏了。
分析:
对于内存移动,首先要考虑:dest和src是不是指向同一内存地址。在这种情况下,就不需要进行任何实际的移动了,如图所示:
其次,我们要考虑两个指针指向的len长度的内存会不会有重叠,如果有重叠的话,直接进行移动有可能会破坏原始数据(在还没移动之前):
在情况2中,dest在src的右边(dest的地址值比src大),且dest与src之间的长度比len小,在这种情况下,如果直接从低地址往高地址复制,那么从dest开始的位置到src+len位置的数据将会被破坏。
在情况3中,因为dest与src的距离大于len,所以不会出现重叠的情况。
在情况4中,dest的地址值比src小(即dest在src的左边),如果src与dest的距离比len小,虽然会出现重叠的情况,但是却不会造成数据的损坏。因为重叠那部分数据在被替换前已经被移走。因此在这种情况下,不管dest和src之间的距离是多大,从低地址向高地址移动是没有问题的。
代码实现:
在面试的时候,我傻傻地把所有情况都用一个if来做判断,然后用几个指针来避免数据破坏,其实,并不需要这么麻烦。
当dest在src的左边(即dest的地址值比src的小)时,只需要从左往右赋值(即从低地址开始复制);当dest在src的右边(即dest的地址值比src的大),只需要从右往左开始赋值就行了(即从高地址开始复制)。使用这种方法,即使发生重叠,也能避免数据的破化。
1 void* MyMemMove(void *dest, const void *src, size_t nBytes){ 2 void *ret = dest; //用于返回 3 4 const char *from = static_cast<const char*>(src); 5 char *to = static_cast<char*>(dest); 6 7 if( dest < src ){ //dest在src的左边 8 while( nBytes-- ) //从左往右复制 9 *to++ = *from++; 10 }else if( dest > src ){ //dest在src的右边 11 from += nBytes - 1; //从右往左复制 12 to += nBytes - 1; 13 while( nBytes-- ) 14 *to-- = *from--; 15 } 16 return ret; 17 }
写完之后,在博客园看到这篇写得挺简洁的,推荐一下:http://www.cnblogs.com/kekec/archive/2011/07/22/2114107.html