题目描述:
写出完整版的strcpy函数
代码1:
char * my_strcpy(char *str1,const char *str2) //[1]
{
assert(str1 != NULL && str2 != NULL); //[2]
char *ret = str1; //[3]
while (*str2!='\0')//[4]
{
*str1= *str2;
str1++;
str2++;
};
*(str1+1) = '\0';
return ret;
}
分析1:
1.为什么用const修饰str2?
用const修饰原始字符串,防止原始字符串被修改。
2.为什么要有空指针检查?
不检查指针的有效性,说明答题者不注重代码的健壮性。
3.为什么返回值要返回目标地址并且返回值类型要为char*?
返回char*类型可以使函数支持链式表达式,例如:int i = strlen(strcpy(str1,str2));又如,char * str1=strcpy(new char[10],str2);返回str2的原始值是错误的。其一,源字符串肯定是已知的,返回它没有意义。其二,不能支持形如第二例的表达式。其三,把const char *作为char *返回,类型不符,编译报错。
4.如果str1,str2内存重叠,怎么办?
如果str1,str2内存发生重叠,例如strcpy(str1+1,str1),我们赋值会在赋值时将str1中的字符进行修改,并且将str1的’\0’覆盖掉,while循环就无法正常退出。所以我们还需要考虑到内存重叠的情况下怎么处理。
完整的正确代码:
char * my_strcpy(char *dst,const char *src)
{
assert(dst != NULL && src != NULL);
char *ret = dst;
my_memcpy(dst, src, strlen(src)+1);
return ret;
}
char *my_memcpy(char *dst, const char* src, int cnt)
{
assert(dst != NULL && src != NULL);
char *ret = dst;
if (dst >= src && dst <= src+cnt-1) //dst地址高于src地址并且有重复部分,从高地址开始复制
{
dst = dst+cnt-1;
src = src+cnt-1;
while (cnt--)
*dst-- = *src--;
}
else //正常情况或者dst地址低于src地址,从低地址开始复制
{
while (cnt--)
*dst++ = *src++;
}
return ret;
}
主函数调用:
int main
{
char str1[100] = "hello";
char str2[100] = "hello,world";
char str3[100] = "";
char *str4 = my_strcpy(str1+1,str1);
char *str5 = my_strcpy(str3,str2);
cout<<"str1=>"<<str1<<endl;
cout<<"str4=>"<<str4<<endl;
cout<<"str5=>"<<str5;
return 0;
}
调用结果:
分析2:
1.str1的内存地址高于str2的内存地址,我们就要从高地址开始赋值,这样我们才能得到我们需要的字符串
2.str1的内存地址小于str2的内存地址或者正常情况下,我们就直接从低地址开始赋值便可。
3.为什么my_strcpy函数的第二个参数为const char*类型,结果函数执行后str1的值被修改两者之间不冲突?
const char* 类型,定义一个指向字符常量的指针,这里,ptr是一个指向 char* 类型的常量,所以不能用ptr直接或者间接来修改所指向的内容,换句话说,*ptr的值为const,不能修改。但是ptr的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对ptr而言,这个值是常量。实验如下:ptr指向str,而str不是const,可以直接通过str变量来修改str的值,但是确不能通过ptr指针来修改,实验如下: