首先我们先来认识一下strcpy这个函数,该函数的作用是将字符串1的内容拷贝到字符串2中,
声明方式为
char * strcpy ( char * destination, const char * source );
其中destination所指向的地址是上文中的字符串2,source是字符串1上的地址
模拟strcpy前我们先来熟悉一下strcpy的用法
int main()
{
char str[20] = { 0 };
strcpy(str, "hello");
printf("%s\n", str);
return 0;
}
代码打印出的结果就是hello
那么下面我们来模拟实现strcpy
一、最基本的思想
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
}
该代码中我们将src中每一个字符利用循环体的结构分别拷贝给dest,循环体用src != ‘\0’作为条件语句,当src指向’\0’的时候循环跳出,此时’\0’并没有被拷贝入dest,因此我们在循环跳出的时候需要追加一个*dest = *src。
二、实现过程优化
我们通过最基本的代码了解了strcpy的实现过程,下面就要对最初的代码进行优化
优化代码如下
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest++ = *src++;//hello的拷贝
}
*dest = *src;//\0的拷贝
}
该代码在实现的过程中将循环体内部代码实现进行了一个优化,后置++表示先赋值再++,即在循环体内部我们先将src指向字符的值赋给dest指向的字符,然后src和dest再向后移动一个字节,这与我们最初的代码的实现过程完全一致。
三、实现过程进一步优化
void my_strcpy(char* dest, const char* src)
{
while (*dest++ = *src++)
{
;
}
}
(1)当*dest++ = *src++作为一个判断条件时,这个式子的值为该次src拷贝给dest的字符的值,因此我们再来看这个循环,在src指向‘\0’之前,每一次的循环中条件语句的结果都是一个字符,为真,所以进入循环,并且条件语句在给出值的同时也让src和dest两个指针向后各自移动一个字节,保证拷贝字符的顺利进行,当条件语句给出的值为‘\0’时,’\0’的asc码值为0,说明条件语句为假,循环跳出,此时’\0’已经赋给了dest,故不需要额外加一次赋值。
(2)此外,在此次修改中我们在函数的形src之前加上了一个const,目的是为了防止使用者在使用strcpy函数时将dest和src两个实参输反了,例如:
my_strcpy(dest,src)//正确写法
my_strcpy(sre,dest)//使用者写法
使用者的写法会带来很多问题,最直接的一个问题就是会导致结果出错(本来想把1拷给2,最后结果把2拷给了1),其次就是因为两个字符串的长度很可能不一样,反过来拷贝的话会出现将长的字符串拷贝到短的字符串中,结果会导致程序崩溃。但如果我们在src前面加上const,当程序按照使用者的写法走起来时系统会在my_strcpy函数使用的那一行报错,提示使用者两个位置输反了,从而避免错误结果的产生。
从另一个角度来说,strcpy的本质就是将src的内容拷贝进dest指向的空间中,dest内容改变而src内容不变,所以基于这个角度,我们也应该给形参src前面加上一个const来保证src内容不被改变。
四、安全性优化
#include《assert.h>
void my_strcpy(char* dest, const char* src)
{
assert(src != NULL);
assert(dest != NULL);
while(*dest++=*src++)
{
;
}
}
在这段代码中我们断言src和dest不为空指针,因为空指针时不能进行解引用操作的,强行操作会使代码无法运行,而我们断言之后,如果src是空指针的话,在程序运行的过程中会反馈断言失败,我们可以很快地发现问题并解决问题。
五、返回值优化
最后,对比我们现在写的strcpy和库函数中的strcpy,我们发现这二者的返回值不同
翻译过来,strcpy返回的是目标空间的起始地址,这样做的话可以更加便于我们查看修改后的字符串,因此我们给出strcpy的最后一次优化
#include《assert.h>
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(src != NULL);
assert(dest != NULL);
while(*dest++ = *src++)
{
;
}
return ret;
}
到这里我们strcpy的模拟实现就全部结束啦,小编水平有限,编写过程中难免出错,如有错误欢迎读者及时指正!