本文引出memcpy的问题,并提供一个实现方式。
参考了[【C/C++】实现memcpy函数]
问题
首先来看memcpy的定义:
void *memcpy(void *dest, const void *src, size_t n);
//If copying takes place between objects that overlap, the behavior is undefined.
对于内存重叠,比如src在dst之前的情形,此时src还没有完成复制,但是已经和dst重合,从而src前面的值将后面的值覆盖,那么后面的值无法再进行对dest进行复制。
考虑如下代码,buf+3与buf内存覆盖,所以输出行为无法预测。总之不能输出正确的结果。
当然,可以用memmove实现,后者是引入了一个临时数组暂时存储src的值,从而可以完成复制。
/c
#include <stdio.h>
#include <string.h>
#define LEN 128
int main( void ){
char buf[LEN] = "hello,world!";
char* ret = memcpy( buf+3, buf, strlen(buf) );
ret[strlen(buf)] = 0;
printf( "%s\n", ret );
/*
char* ret = memmove( buf+3, buf, strlen(buf) );
ret[strlen(buf)] = 0;
printf( "%s\n", ret );
*/
return 0;
}
下面给出一种实现,当内存重叠的时候,需要从后向前复制。
void* Memcpy( void* dest, void* src, size_t n ){
char* psrc = (char*)src; // 此处必须强转,否则通用指针并不关联类型,++操作以及psrc+n操作无法实现。
char* pdst = (char*)dest;
if( !dest || !src ){
return NULL;
}
if( ( psrc < pdst ) && ( psrc + n > pdst) ){ // 从后向前拷贝
psrc = psrc + n - 1;
pdst = pdst + n - 1;
while( n-- ) *pdst-- = *psrc--;
}
else{// 从前向后拷贝
while( n-- ) *pdst++ = *psrc++;
}
return dest;
}
补充
早上再次复习了memcpy,有新的收获在此补充!。
1. memcpy是 copy of block,它的本质是内存拷贝。它可以适用于字符串的拷贝,但是并不是仅仅适用于字符串,int[], 或者其它类型都是适用的。具体拷贝的时候,按照字节进行拷贝,但是也可以按照CPU字长进行拷贝。
2. 不是遇见’\0’结束,而是必须拷贝num字节。这是主要是与strcpy的区别。
3. 需要以下两个注意:
- overlap的问题
- 溢出的问题,必须保证拷贝的字节数n不超过src以及dest的大小。这一点在程序中是没有办法保证的。因为对于strcpy来说,它可以计算strlen,但是像int[]数组,没法计算。所以,这点需要认为保证。