C/C++ strcpy() 函数实现
已知 strcpy() 函数的原型是:
char * strcpy(char * strDest,const char * strSrc);
1. 不调用库函数,实现strcpy函数。
char* myStrcpy(cahr * dest, const char * src){
if(dest == nullptr || src == nullptr || dest == src){
return dest;
}
char * temp = dest;
while(*src != '\0'){
*dest++ = *src++;
}
*dest = *src; // 拷贝'\0'
return temp; // 返回原首地址
}
优化:
#include <assert.h>
char* myStrcpy(char * dest, const char * src){
assert(dest != nullptr && src != nullptr); // assert 断言,括号内为真时跳过,否则退出程序
if(dest == src) return dest;
char * temp = dest;
while(*dest++ = *src++){
// while((*dest++ = *src++) != '\0')
;
}
return temp; // 返回原首地址
}
2. 解释为什么要返回char *
为了让 strcpy() 实现链式表达式,如 int length = strlen( strcpy( strDest, “hello world”) );
3. 考虑内存重叠的情况
对于strcpy而言,该函数并没有考虑内存重叠的问题,例如
char s[10] = "hello";
strcpy(s, s+1); // 返回ello
// strcpy(s+1, s); // 应返回 hhello,但实际会报错,因为 dest 与 src 重叠了,把'\0'覆盖了
所谓内存重叠,就是 src 未处理的部分已经被 dest 给覆盖了,只有一种情况:
src <= dest <= src + strlen(src)
,即目标首地址在源地址段中间。
C函数 memcpy 自带内存重叠检测功能,下面给出 memcpy 的实现 my_memcpy,当检测到内存重叠时,从高地址开始往地址遍历赋值,否则从低地址到高地址赋值。
#include <assert.h>
#include <cstring>
#include <iostream>
using namespace std;
char* mymemcpy(char* dest, const char* src, int len){
// 内存复制,因此对于字符串,长度len应包含'\0'结束符
assert(dest != nullptr && src != nullptr);
if(dest == src) return dest;
char* temp = dest;
// 当检测到内存重叠时,从高地址开始往地址遍历赋值,否则从低地址到高地址赋值
if(dest > src && dest <= src + len - 1){
cout << "high to low addr" << endl;
dest = dest + len - 1; // 最高地址开始
src = src + len - 1;
while(len--){
*dest-- = *src--;
}
}else{
while(len--){
*dest++ = *src++;
}
}
return temp;
}
char* myStrcpy(char * dest, const char * src){
assert(dest != nullptr && src != nullptr); // assert 断言,括号内为真时跳过,否则退出程序
if(dest == src) return dest;
char * temp = dest;
// while(*dest++ = *src++){ // while((*dest++ = *src++) != '\0') // 不带重叠检测,从低到高地址复制
// ;
// }
mymemcpy(dest, src, strlen(src) + 1); // 带内存重叠检测,长度为 strlen(src) + 1
return temp; // 返回原首地址
}
int main(){
char s1[10] = "hello";
char s2[10] = "123";
cout << myStrcpy(s1 + 2, s1) << endl;
return 0;
}