首先一般人会这样先出来:

#include<stdio.h>
void my_strcpy(char* dest,char* src)
{
  while(*src!='\0')
  {
  *dest=*src;
  *dest++;
  *src++;
  }
  *dest=*src;//'\0'
}
int main()
{
  char arr1[]="########";
  char arr2[]="hello";
  my_strcpy(arr1,arr2);
  printf("%s\n",arr1);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

但是如果只是写到这,面试官满分十分只会给你6分,下面我会一步步说失去的那4分在哪,同时慢慢优化代码。

1.第一步优化:

我们可以发现:while循环中的三句话,其实可以变成一句话:

*dest++=*src++(后置++:先使用后加加)

这样还不够,可以直接将原来my_strcpy函数中的代码变成:

while(*dest++=*src++)
{
  ;
}
  • 1.
  • 2.
  • 3.
  • 4.

注:‘\0’的返回值是0

目前代码已经值7分了

2.第二步优化

目前的代码是要将arr2拷贝到arr1中,但是如果有人不小心传参传错了,不是将arr2拷贝到arr1中去,而是将NULL传到了arr1,而NULL是个空指针,这最后会导致野指针的问题。

我也在之前的文章中写到过野指针的造成原因,我讲到当我们用指针时首先要判断指针是否是空指针。所以,我们又有了一个可以改进的地方。

void my_strcpy(char* dest,char* src)
{
  if(dest!=NULL&&src!=NULL)
  {
    while(*dest++=*src++)
    {
      ;
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

但是这样还是存在问题,大家仔细想想:NULL传参过去是有问题的,我们写代码出现错误的时候应该解决问题才对,但是如果使用if语句来作为前提的话就回避了问题的所在。所以我们不采取这样的方法。

于是我们继续改造代码:

#include<stdio.h>
#inlcude<assert.h>//assert需要加头文件
void my_strcpy(char* dest,char* src)
{
  assert(dest!=NULL&&src!=NULL)//断言
    while(*dest++=*src++)
    {
      ;
    }
}
int main()
{
  char arr1[]="########";
  char arr2[]="hello";
  my_strcpy(arr1,NULL);
  printf("%s\n",arr1);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

assert和判断是否是NULL的if语句不同是:assert可以告诉你错在哪:

面试小题:模拟字符串函数拷贝(一步步教你提升代码质量)_野指针

目前代码值个8分

3.第三步优化

面试小题:模拟字符串函数拷贝(一步步教你提升代码质量)_c++_02

根据cplusplus.com网站中关于strcpy的用法讲解,我们可以发现我们代码中的第二个参数前面并没有   const,而标准的strcpy有const;还有我们设计的函数的返回类型是void,而它的是char*。

所以当我们将这两点都改正了,我们的这段代码就可以给到10分。但是为什么呢??

const:我们应该都知道是常属性,让一个值不能被改变。

我们原代码目的是想将arr2的字符串拷贝到arr1中,但是如果我们一不小心将来源(source)和目的地(destination)搞反了,这样找出问题会很麻烦,只能尝试调试的方法,所以我们要加个const

void my_strcpy(char* dest,const char* src)//const目的是让源头数据*src不能被改变,起保护作用
  //注意:目的地的不能拿const修饰,因为目的地一定会被改变
{
  assert(dest!=NULL&&src!=NULL)//断言
    while(*dest++=*src++)
    {
      ;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

现在代码已经是9分类

4.第四步优化

第三步优化中也已经提到了,我们创建的函数的返回类型是void,是和标准不同的,现在我们也将自己代码的返回类型设置成char*

#include<stdio.h>
#inlcude<assert.h>//assert需要加头文件
char* my_strcpy(char* dest,char* src)
{
  char* ret=dest;
  assert(dest!=NULL&&src!=NULL)//断言
    while(*dest++=*src++)
    {
      ;
    }
  return ret;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

最后这个函数返回的是目的地的地址,因为本身就是用char*接收的,所以main函数中也应该直接接收函数的返回值

int main()
{
  char arr1[]="########";
  char arr2[]="hello"printf("%s\n",my_strcpy(arr1,arr2));
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

最后,满分代码如下所示:

#include<stdio.h>
#inlcude<assert.h>
char* my_strcpy(char* dest,char* src)
{
  char* ret=dest;
  assert(dest!=NULL&&src!=NULL)
    while(*dest++=*src++)
    {
      ;
    }
  return ret;
}
int main()
{
  char arr1[]="########";
  char arr2[]="hello"printf("%s\n",my_strcpy(arr1,arr2));
  return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.