Strcpy,memcpy函数的内存重叠

来源:互联网 发布:个性头像制作软件 编辑:程序博客网 时间:2024/06/06 11:45

最近想要换工作,所以复习了下C语言的知识点,在看有些面试题跟博客时发现了些问题,我在这里总结下。

大部分对strcpy考察题目是这样的,给定char * strcpy(char * strDest,const char * strSrc);原型,然后接下来是写出他的实现。

char * my_strcpy(char * strDest,const char * strSrc)        {                if ((strDest==NULL)||(strSrc==NULL)) //[1]                        throw "Invalid argument(s)"; //[2]                char * strDestCopy=strDest;  //[3]                while ((*strDest++=*strSrc++)!='/0'); //[4]                return strDestCopy;        }

然后呢是1,2,3,4哪里错了扣哪里分。其实这个不是strcpy真正的实现(被骗了好多年吧,我也是看了这位博主才知道的)。为什么说strcpy不是真正的实现呢。

测试下就知道了。如下代码:

char str[10]="abc";my_strcpy(str+1,str);
如果这样调用的话,就会出现崩溃了。

但是如果用标准库中的strcpy,不仅没有崩溃,如果打印的话还会打印出:aabc

char str[10]="abc";strcpy(str+1,str);
所以strcpy的真正实现方式可能是以下的方式,(仅供参考)

char *my_strcpy(char *dst,const char *src){assert(dst != NULL);assert(src != NULL);char *ret = dst;memcpy(dst,src,strlen(src)+1);return ret;}

那么问题来了,memcpy有没有很好的处理内存覆盖问题呢,其实这个也可以编写一个简单的测试语句用来测试下,

char buf[10] = "123456789";memcpy(buf + 2,buf,5);printf("%s\n",buf);
如果

打印:121234589说明很好的处理了内存重叠。

打印:121212189说明内存重叠没有处理。
但是在ubuntu下打印出的是: 121234389,奇怪哦。

在Windows下VC6.0下打印的是:121234589,奇怪哦。

centos下打印的是:121214589,各种奇葩结果哦。


所以Memcpy是不考虑内存重叠的,其实好多人博客上也提到了memcpy有内存重叠的问题,我们使用的是可以用memove来代替,或者使用memcpy_s(此函数适合VS2005以上版本)。

strcpy跟memcpy都没有处理内存重叠。

附录:

//vc++ memcpy28:           char buf1[10] = "123456789";00401178   mov         eax,[string "123456789" (00431034)]0040117D   mov         dword ptr [ebp-0Ch],eax00401180   mov         ecx,dword ptr [string "123456789"+4 (00431038)]00401186   mov         dword ptr [ebp-8],ecx00401189   mov         dx,word ptr [string "123456789"+8 (0043103c)]00401190   mov         word ptr [ebp-4],dx29:        memcpy(buf1+2,buf1,5);00401194   push        500401196   lea         eax,[ebp-0Ch]00401199   push        eax0040119A   lea         ecx,[ebp-0Ah]0040119D   push        ecx0040119E   call        memcpy (004084b0)004011A3   add         esp,0Ch//vc++  strcpy17:       char buf[10] = "123";004010D8   mov         eax,[string "123" (00431020)]004010DD   mov         dword ptr [ebp-0Ch],eax004010E0   xor         ecx,ecx004010E2   mov         dword ptr [ebp-8],ecx004010E5   mov         word ptr [ebp-4],cx18:       strcpy(buf+1,buf);004010E9   lea         edx,[ebp-0Ch]004010EC   push        edx004010ED   lea         eax,[ebp-0Bh]004010F0   push        eax004010F1   call        strcpy (00408380)004010F6   add         esp,8

//linux memcpy        .cfi_startproc        pushq   %rbp        .cfi_def_cfa_offset 16        .cfi_offset 6, -16        movq    %rsp, %rbp        .cfi_def_cfa_register 6        subq    $16, %rsp        movl    $875770417, -16(%rbp)        movl    $943142453, -12(%rbp)        movw    $57, -8(%rbp)        leaq    -16(%rbp), %rax        leaq    -16(%rbp), %rdx        leaq    2(%rdx), %rcx        movl    $5, %edx        movq    %rax, %rsi        movq    %rcx, %rdi        call    memcpy        leave//linux strcpy        .cfi_startproc        pushq   %rbp        .cfi_def_cfa_offset 16        .cfi_offset 6, -16        movq    %rsp, %rbp        .cfi_def_cfa_register 6        subq    $16, %rsp        movq    $3355185, -16(%rbp)        movw    $0, -8(%rbp)        leaq    -16(%rbp), %rax        leaq    -16(%rbp), %rdx        addq    $1, %rdx        movq    %rax, %rsi        movq    %rdx, %rdi        call    strcpy






0 0