最近想要换工作,所以复习了下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++ memcpy
28: char buf1[10] = "123456789";
00401178 mov eax,[string "123456789" (00431034)]
0040117D mov dword ptr [ebp-0Ch],eax
00401180 mov ecx,dword ptr [string "123456789"+4 (00431038)]
00401186 mov dword ptr [ebp-8],ecx
00401189 mov dx,word ptr [string "123456789"+8 (0043103c)]
00401190 mov word ptr [ebp-4],dx
29: memcpy(buf1+2,buf1,5);
00401194 push 5
00401196 lea eax,[ebp-0Ch]
00401199 push eax
0040119A lea ecx,[ebp-0Ah]
0040119D push ecx
0040119E call memcpy (004084b0)
004011A3 add esp,0Ch
//vc++ strcpy
17: char buf[10] = "123";
004010D8 mov eax,[string "123" (00431020)]
004010DD mov dword ptr [ebp-0Ch],eax
004010E0 xor ecx,ecx
004010E2 mov dword ptr [ebp-8],ecx
004010E5 mov word ptr [ebp-4],cx
18: strcpy(buf+1,buf);
004010E9 lea edx,[ebp-0Ch]
004010EC push edx
004010ED lea eax,[ebp-0Bh]
004010F0 push eax
004010F1 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