编写一个标准strcpy函数

1、如题,编写字符串的拷贝函数,下面就一些答案,分析出完美的解答。


2、strcpy实现1:

void MyStrcpy1(char *strDest, char *strSrc)
{
     if  (strDest == NULL || strSrc == NULL)
     {
         return ;
     }
 
     int i = 0;
 
     while  (*(strSrc + i) !=  '\0' )
     {
         *(strDest + i) = *(strSrc + i);
         i++;
     }
}

调用1:

int _tmain(int argc, _TCHAR* argv[])
{
     char str1[12] = {0};
     char str2[] =  "abcdef" ;
 
     MyStrcpy1(str1, str2);
     printf( "%s\n" , str1);
 
     getchar();
     return  0;
}

结果1:正确



调用2:目的字符数组不初始化

int _tmain(int argc, _TCHAR* argv[])
{
     char str1[12];
     char str2[] =  "abcdef" ;
 
     MyStrcpy1(str1, str2);
     printf( "%s\n" , str1);
 
     getchar();
     return  0;
}

结果2:错误



调用3:

int _tmain(int argc, _TCHAR* argv[])
{
     char str1[1] = {0};
     char str2[] =  "abcdef" ;
 
     MyStrcpy1(str1, str2);
     printf( "%s\n" , str1);
 
     getchar();
     return  0;
}

结果3:错误



分析:这个函数写的应该比较清晰了,而且也考虑到了传入参数(指针)可能为空的情况,但是有以下几点问题:

(1)源字符串的末尾的'\0'没有拷贝到目标中,如果传入的strDest原来就是字符串,那么OK;但是如果传入的strDest只是一个字符数组的地址,或者说一块内存空间的地址(内存空间又未初始化为NULL),那么就会出问题了。

(2)传入的strSrc参数可能被更改,应加const限定。

(3)为了能够使用链式表达式,应该加上返回值(返回目的指针)。

(4)最好,能用断言,检测参数的合法性。


优化实现1如下:

char* MyStrcpy1(char *strDest, const char *strSrc)
{
     if  (strDest == NULL || strSrc == NULL)
     {
         return  strDest;
     }
 
     int i = 0;
     char *pCh = strDest;
 
     while  (*(strSrc + i) !=  '\0' )
     {
         *(strDest + i) = *(strSrc + i);
         i++;
     }
 
     *(strDest + i) =  '\0' ;
 
     return  pCh;
}

或用for循环:

char* MyStrcpy1(char *strDest, const char *strSrc)
{
     if  (strDest == NULL || strSrc == NULL)
     {
         return  strDest;
     }
 
     int i = 0;
     char *pCh = strDest;
 
     for  (i = 0; *(strSrc + i) !=  '\0' ; i++)
     {
         *(strDest + i) = *(strSrc + i);
     }
 
     *(strDest + i) =  '\0' ;
 
     return  pCh;
}

或直接用下标操作:

char* MyStrcpy1(char *strDest, const char *strSrc)
{
     if  (strDest == NULL || strSrc == NULL)
     {
         return  strDest;
     }
 
     int i = 0;
     char *pCh = strDest;
 
     for  (i = 0; strSrc[i] !=  '\0' ; i++)
     {
         strDest[i] = strSrc[i];
     }
 
     strDest[i] =  '\0' ;
 
     return  pCh;
}

最后,可以在最前面加上断言:

assert( (strDest != NULL) && (strSrc != NULL) );

但是,assert只在Debug下有用,在Release下是无效的。


3、更进一步,因为strDest是指针而不是数组名,所以可以直接进行自增、自减运算:

char* MyStrcpy1(char *strDest, const char *strSrc)
{
     assert( (strDest != NULL) && (strSrc != NULL) );
 
     if  (strDest == NULL || strSrc == NULL)
     {
         return  strDest;
     }
 
     char *pCh = strDest;
 
     while  (*strSrc !=  '\0' )
     {
         *(strDest++) = *(strSrc++);
     }
 
     *strDest =  '\0' ;
 
     return  pCh;
}

这样,你会发现代码还可以精简:

char* MyStrcpy1(char *strDest, const char *strSrc)
{
     assert( (strDest != NULL) && (strSrc != NULL) );
 
     if  (strDest == NULL || strSrc == NULL)
     {
         return  strDest;
     }
 
     char *pCh = strDest;
 
     while  (( *(strDest++) = *(strSrc++) ) !=  '\0' )
     {
         NULL;
     }
 
     return  pCh;
}


4、说明:

(1)vs2010中strcpy的定义如下:

/***
*char *strcpy(dst, src) - copy one string over another
*
*Purpose:
*       Copies the string src into the spot specified by
*       dest; assumes enough room.
*
*Entry:
*       char * dst - string over which "src" is to be copied
*       const char * src - string to be copied over "dst"
*
*Exit:
*       The address of "dst"
*
*Exceptions:
*******************************************************************************/
 
char * __cdecl strcpy(char * dst, const char * src)
{
         char * cp = dst;
 
         while ( *cp++ = *src++ )
                 ;                /* Copy src over dst */
 
         return ( dst );
}


(2)另外,关于函数中的assert和if判断,都是加强代码安全的一种手段,对于功能本身并不是必须的,assert出错表示发生了不该发生的事,这时就需要检查代码。另外,我们一直说在使用指针之前,要判断是否为空,这也是为了避免可能出现的错误。




  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值