关于memcpy
对于memcpy,网上对其的实现大多是简单的循环拷贝,如果拷贝的时候存在交叉,就可能出问题:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 void *memcpy(void *memTo, const void *memFrom, size_t size) 7 { 8 if((memTo == NULL) || (memFrom == NULL)) //memTo和memFrom必须有效 9 return NULL; 10 char *tempFrom = (char *)memFrom; //保存memFrom首地址 11 char *tempTo = (char *)memTo; //保存memTo首地址 12 while(size -- > 0) //循环size次,复制memFrom的值到memTo中 13 *tempTo++ = *tempFrom++ ; 14 return memTo; 15 } 16 17 int main() { 18 char name[10] = "123456"; 19 //将字符串向后移一位 20 memcpy(name + 1, name, strlen(name) - 1); 21 printf("%s\n", name); 22 return 0; 23 }
程序输出的是“111111”,而不是112345。但是,如果调用系统的memcpy函数,确能得到正确的结果(环境:win7 64bit,visual 2008)。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int main() { 7 char name[10] = "123456"; 8 //将字符串向后移一位 9 memcpy(name + 1, name, strlen(name) - 1); 10 printf("%s\n", name); 11 return 0; 12 }
程序输出的是112345。可见自带的memcpy已经能够正确实现交叉拷贝(虽然网上都说memcpy不能处理交叉时候的拷贝)。
所以,memcpy的实现到底是怎样的呢。对于void* memcpy(void *des, void *src, int n);
1.当des <= src的时候,字符串能够正确从左到右拷贝,因为des覆盖src的时候,src处的字符串已经没用了。
2.当des > src且des - src >= n时,复制的片段没有交叉,所以能够正常拷贝。
3.当des > src且des - src < n时,从左到右拷贝时,src中待拷贝的片段会被前面的覆盖掉,解决的办法是将拷贝的顺序改成从右向左。这样des覆盖src的时候,src处的字符串已经没用了,有点像1处的情况。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 void *memcpy(void *des, const void *src, size_t size) 7 { 8 if((des == NULL) || (src == NULL)) 9 return NULL; 10 11 char *tempSrc, *tempDes; 12 if((unsigned char*)des <= (unsigned char*)src || //1.des <= src 13 (unsigned char*)des - (unsigned char*)src >= size) //2.des > src且des - src >= n 14 { 15 tempSrc = (char *)src; 16 tempDes = (char *)des; 17 while(size -- > 0) 18 *tempDes++ = *tempSrc++ ; 19 } 20 else { //3.des > src且des - src < n 21 tempSrc = (char *)src + size - 1; 22 tempDes = (char *)des + size - 1; 23 while(size -- > 0) 24 *tempDes -- = *tempSrc --; 25 } 26 return des; 27 } 28 29 int main() { 30 char name[10] = "123456"; 31 //memcpy(name, name + 1, strlen(name) - 1); //1.des <= src 32 //memcpy(name + 3, name, 3); //2.des > src且des - src >= n 33 memcpy(name + 1, name, strlen(name) - 1); //3.des > src且des - src < n 34 printf("%s\n", name); 35 return 0; 36 }