memcpy函数的实现


大致一看题目,memcpy函数,多简单的,核心不就是*dst++ = *src++吗,稍微加个参数检测,搞定。其实不要小看这道题,学问大着呢。


要写好一个完整的memcpy至少要做到以下几点:

1.判断输入指针是否为NULL。(长度可判可不判,因为长度如果<0,后面代码也能处理)

2.考虑内存是否重叠问题。

内存是否重叠问题,即当dst是src的后半部分时,对dst的copy会导致原src后半部分被覆盖,后续的拷贝会出错。(其实linux低下memcpy本身是不处理这种情况的,memmove函数才会考虑内存重叠问题,所以用memcpy函数时,安全性要程序员来保证,参考:http://blog.csdn.net/ce123/article/details/9002276)。

内存重叠需倒序拷贝。

3.高效性。32位总线可以每次复制一个int,64位总线可以一次性复制long long。所以要分成int和char类型来处理,优先int型处理方式。不过要注意,倒序拷贝时,减1必须转化为int类型后减1,*(Int*)dst = *(int *)src填充的才是最后一个int。


代码如下:

#include 
#include 
#include 

void* my_memcpy(void *dst, const void* src, size_t n)
{
    assert(dst != NULL && src != NULL && n >= 0); 
        
    void *ret = dst;  //avoid dst move to back
        
    int wordnum = n >> 2;   //int,x/4
    int slice = n & 3;      //char,x%4

    if(dst <= src || (char*)src+n <= (char*)dst){    //'=' is ok, because the max is src+n-1
        while(wordnum--){
            *(int *)dst = *(int *)src;
            dst = (int *)dst + 1;
            src = (int *)src + 1;
        }   
        while(slice--){
            //*(char* )dst++ = *(char *)src++;   //it will get warning.ISO C++ forbids incrementing a pointer of type ‘const void*’
            *(char *)dst = *(char *)src;
            dst = (char *)dst + 1;
            src = (char *)src + 1;
        }   
    }   
    else{
        dst = (char *)dst + n;
        src = (char *)src + n;
        while(wordnum--){
            dst = (int *)dst - 1;
            src = (int *)src - 1;
            *(int *)dst = *(int *)src;
        }
        while(slice--){
            dst = (char *)dst - 1;
            src = (char *)src - 1;
            *(char *)dst = *(char *)src;
        }
    }

    return ret;
}
注意的就是最后一个int的处理,先加到n,然后减去int*类型的1,然后取出该int。以及ret来保存dst起始地址,防止dst走到最后还需走回来。


测试文件:

int main()
{
    char a[10];
    char b[20] = {"hello"};

    //my_memcpy(a, b, strlen(b)+1);
    //printf("b = %s\n", b); //hello
    //printf("a = %s\n", a); //hello

    my_memcpy(b, b+2, strlen(b)+1);   //'\0'也被拷贝了

    //my_memcpy(b+2, b, strlen(b)+1);
    //printf("b = %s\n", b);       //hehello
    //printf("b+2 = %s\n", b+2);   //hello


    //my_memcpy(b, b, strlen(b)+1);
    //printf("b = %s\n", b); //hello
    //printf("b = %s\n", b); //hello


    return 0;
}



你可能感兴趣的:(面试复习)