strcpy函数实现
但是,并不一定谁都能实现的很好。林锐博士面试微软的时候,就做这个题目。
他也没有把这个题目完全的做对。建议你自己先动手写一个自己的,不要先看
答案。估计有 90%的人写出来的,达不到性能的要求。
标准答案是这样的:
static char * strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *ret = dest;
while ((*dest++ = *src++) != '\0');
return ret;
}
该函数实现了“链式表达式”。
测试了一下,这个函数,在10亿数据规模的复制,在我电脑上大概是 140 ms (release)
下面的写法基本上可以判定是错误:
static char * strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *ret = dest;
while ((*dest = *src) != '\0')
{
dest++;
src++;
}
return ret;
}
可能你会很奇怪,为什么这个是错误的。这个写法大概损失 10%的性能,而且和编译器能优化
的程度有关。原因你看反汇编的代码就知道,指令增加了不少。因为,你要给出一个最优的结果。
但是,似乎还有提升的可能性, 在做这个题目的时候,我首先写出来的是:
static char * strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
int i = 0;
while (*src != '\0')
{
dest[i++] = *src++;
}
dest[i] = '\0';
return dest;
}
别看这算法简单,其实,和标准答案的速度完全一样。为什么,估计要看反汇编。
但是,我总是不相信会这样简单,后来所有题目做好了,还有好多时间,我就想这个算法
的优化,下面是我优化过的算法:
static char * strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *s = (char *)src;
int delt = dest - src;
while ((s[delt] = *s++) != '\0');
return dest;
}
这个算法 很巧妙的回避了一个指针的累加,结果是 96ms 速度提升了近1倍。
///
大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是:
- char *my_strcpy(char *dst,const char *src)
- {
- assert(dst != NULL);
- assert(src != NULL);
- char *ret = dst;
- while((* dst++ = * src++) != '\0')
- ;
- return ret;
- }
1,检查指针有效性;
2,返回目的指针des;
3,源字符串的末尾 '\0' 需要拷贝。
写出上面实现函数就不在话下。
然而这样的实现没有考虑拷贝时内存重叠的情况,下面的测试用例就能使调用my_strcp函数的程序崩溃:
- char str[10]="abc";
- my_strcpy(str+1,str);
然而调用系统的strcpy函数程序正常运行,打印str结果为“aabc”!可见系统strcpy函数的实现不是这样的。
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;
- }
- void * my_memcpy(void *dst,const void *src,unsigned int count)
- {
- assert(dst);
- assert(src);
- void * ret = dst;
- if (dst <= src || (char *)dst >= ((char *)src + count))//源地址和目的地址不重叠,低字节向高字节拷贝
- {
- while(count--)
- {
- *(char *)dst = *(char *)src;
- dst = (char *)dst + 1;
- src = (char *)src + 1;
- }
- }
- else //源地址和目的地址重叠,高字节向低字节拷贝
- {
- dst = (char *)dst + count - 1;
- src = (char *)src + count - 1;
- while(count--)
- {
- *(char *)dst = *(char *)src;
- dst = (char *)dst - 1;
- src = (char *)src - 1;
- }
- }
- return ret;
- }