文章目录
- 前言
- 一、Strcpy库函数是什么?
- 二、Strcpy的用法
- 三、My_Strcpy的实现
- 1.“前菜”
- 2.实现 My_Strcpy 函数
- Ⅰ.“复制过程”的优化
- Ⅱ.“函数内部”的优化
- Ⅲ.“函数形参”的优化
- Ⅳ.“函数返回类型”的优化
- 四、完成 My_Strcpy函数
- 五、感谢大家支持!!!
前言
通过对C语言中 Strcpy 库函数的自我实现,探索程序的 优化之美 ,探索程序的 奥秘!
一、Strcpy库函数是什么?
Strcpy库函数作用:实现字符串的复制
strcpy ( char * destination, const char * source );
实现原理: 将想要复制的字符串地址放在strcpy函数括号的后面,而将复制的字符串的目的地放在括号前面,它们通过传址的方式,实现字符串的复制
通过上面简单的了解,不妨发现, 复制字符串实则可以通过一个一个的字符交换实现复制 ,那我们现在就可以实践实现自定义函数实现Strcpy函数了
二、Strcpy的用法
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
strcpy(arr1,arr2); //1.目标空间的起始地址, 2.原空间的起始地址
printf("%s\n", arr1);
return 0;
}
这里打印的是已经复制过去的字符串
可能有同学要问:“那 arr1数组 里 剩下的 x呢?”
在这里可以观察到:Strcpy 是将 arr2 里的 “hello” 复制到 arr1 中
( 而且是从首元素一个一个覆盖的复制过去 )
本质:是将 arr2 里的 “h e l l o \0” 去覆盖 arr1 里前几个 “x”
也就是说:打印 已完成复制的 arr1 时 ,printf 会打印到 “\0” 前的所有字符,("\0" 为字符串的结束标识符) ,所以会打印到 “\0” 就截止打印
这也就是为什么不会打印后面剩下的“x”了
当我们解决完这个小插曲后,也就基本了解到 Strcpy 的工作原理了
接下来就让我们用自己的语言去实现它吧!
三、My_Strcpy的实现
1.“前菜”
先准备好实现 My_Strcpy 的程序吧
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
My_Strcpy(arr1,arr2); //1.目标空间的起始地址, 2.原空间的起始地址
printf("%s\n", arr1);
return 0;
}
2.实现 My_Strcpy 函数
Ⅰ.“复制过程”的优化
此处忽略“前菜”
直接开始 自定义函数部分
void My_strlen(char* dest,char* src) //dest指针接收目标数组的首元素地址;
//src指针接收要复制的数组首元素地址
{
while(*src != '\0')
{
*dest = *src;
dest++;
src++;
} //但是这样设置循环条件的话,是不会把'\0'也给复制的
//所以得加多一条语句
*dest = *src; //因为上面循环已经让地址到'\0'的地方
//只是循环条件为假,所以不执行
//所以可以承接上面++后的地址,执行一次,即可把'\0'也复制
}
但是有没有什么办法将’\0’也整合在循环里呢?
如果你也有这样的想法
那恭喜你
开始步入“程序之美”
— 优化
那接下来,让我们开始 “优化” 吧!!
为了可以“一步到位”,我们可以尝试把 循环内的条件先整合起来
void My_strlen(char* dest,char* src)
{
while(*src != '\0')
{
*dest++ = *src++; //跟之前意思一样
//先复制,然后地址++,然后解引用 复制
}
*dest++ = *src++;
}
开始“一步到位”吧
void My_strlen(char* dest,char* src)
{
while(*dest++ = *src++)
{
; //上面的条件,既可以先复制
} //当复制'\0'后,条件判断为假,又可以退出循环
} //这样不就能做到“一步到位”、“一石二鸟”了吗!
看到这里
是不是可以感受到 “程序” 所带给人“醍醐灌顶”的感觉了呢?
接下来
还有更 “妙” 的呢!!
Ⅱ.“函数内部”的优化
为了保证函数的可实行性
我们要判断传过来的是否为空指针
这就是 “优化” 的第二个点啦~
此判断操作,我们可以用 “assert()” – 断言 这个库函数
【这里不细致展开】
那我们就可以用此来判断传过来的两个指针是否为空指针
从而确保函数的可执行性和正确性~
void my_strcpy(char*dest , const char*src)
{
//判断传过来的 是否为空指针
assert( src != NULL);//断言----需要引头文件 <assert.h>
// 如果 != 则 为真--则不会报错,
//如果为假(即 指针为 空指针)--则会报错
assert( dest != NULL);
while (*dest++ = *src++)
{
;
}
}
加上 assert 还有一个好处就是:如果为空指针,程序也可以快速给出出错的位置 (这就是 if 语句所做不到的)
就像下面一样:
这样的程序用起来谁不放心呢~
Ⅲ.“函数形参”的优化
通过回看前面 “Strcpy库函数是什么” 的章节时
我们不难发现
我们的 My_Strcpy 函数 与 Strcpy库函数 对比起来
还是有 “不同的”
说明我们还有 “优化” 的空间哦!
不难发现
对比我们的 My_Strcpy 函数 的形参部分
这里的 “形参” 部分多了 “const” 来修饰
我们此刻就要开始思考–为什么要这样做呢
【PS:要做到这种 勤加思考 的习惯,才是一个优秀的程序标配哦~】
这样做可以保证 在复制的过程中,保护“复制的内容”不会在复制的 过程中而被改变
【PS:这里暂时不细谈“const操作符在指针中的应用”!】
如果大家觉得这篇文章写得不错、觉得通俗易懂
可以多多点赞、转发、收藏哦!
本作者会尽快出这方面相关的内容哦!!
回归正题
在 * 前 加上 ‘const’
表示 * source (对应回 My_Strcpy 中的 ’ * src ’ ) 即 * source这个指针 解引用后所对应的内容 具有 常属性,在复制的过程中, source的值不会被改变*
只有当 source的地址发生改变,即 source所对应的内容也发生改变时,它的值才会发生改变
这也就可以有效避免如下的问题
void My_strlen(char* dest,const char* src) ![在这里插入图片描述](https://img-blog.csdnimg.cn/66a1220bbfbe4150bb78364a367522ee.png#pic_center)
{
while( *src++ = *dest++)
{
; //复制的时候,放错位置的情况
}
}
发生上述问题时,程序就会自动报错,保护了程序
因为此时 *src 具有常属性
相当于赋值的时候,常量不能放在等号的左边一个道理
把src指向的内容拷贝放进dest 指向的空间中
从 本质上讲,就是希望dest指向的内容被修改,src指向的内容不被修改
这也就是我们所”优化”的另一个点啦~
Ⅳ.“函数返回类型”的优化
再次对照 Strcpy库函数
我们又不难发现,Strcpy库函数 的返回类型竟然是 char*
这不
“优化” 又来了~~
Strcpy这个库函数,其实返回的是目标空间的起始地址
那我们就可以做如下 “优化”
#include <stdio.h>
#include <string.h>
char* my_strcpy(char*dest , const char*src)
{
char * ret = dest; //先保存起始地址下来
assert(*src != NULL)
assert(*dest != NULL);
while (*dest++ = *src++)
{
;
}
return ret; //内容改变了,但地址没变--也就依旧可以使用了
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", My_Strcpy(arr1,arr2)); //这里就可以 “链式访问”
//即【函数的返回值 为 printf的参数】
//这样就可以很快的查看 目标空间内容是什么
return 0;
}
使用 char * 返回类型,可以更快地查看 目标空间内容是什么啦~~
四、完成 My_Strcpy函数
综上,
我们就成功的将 My_Strcpy函数 ,所有可以优化的点都有优化好啦~
换句话说:我们成功的复刻了 Strcpy函数
是不是顿时感觉自己棒棒哒!!
但这只是**“小巫见大巫”**,起到为各位同学 “抛砖引玉” 的作用,希望同学们也可以 借此文章对个人思想有所启发哦!
程序世界之大,
还有更多未知的等待你们
去探索,
去发现,
去找到属于你们豁然开朗的那一刻哦~
五、感谢大家支持!!!
【如果你觉得本文对你有帮助,可以点点赞 支持一下哟~】
【如果你有更好的想法,也可以在下方评论哟,相互学习,相互进步!】