当前位置: 首页 > news >正文

C语言--模拟实现库函数strcpy

目录

  • 前言
  • strcpy实现的基本原理
  • 函数的模拟实现
    • 代码优化
      • assert--断言
      • const关键字
  • strcpy的返回值
  • 结语

前言

本章内容我们将通过相关函数来实现库函数中的strcpy。

strcpy实现的基本原理

C语言 strcpy()函数用于对字符串进行复制(拷贝)。需要的头文件为 <string.h>。原理如下

char* strcpy(char* strDestination, const char* strSource);

其中的strSource为源字符串,strDestination为目的字符串,strcpy的作用就是将 strSource 指向的字符串复制到 strDestination。

我们举个例子

int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

打印结果如图1
图1
我们知道字符串arr2实际上是"hello\0",那么我们在打印字符串的时候有没有打印这个\0呢,我们用监视的方法来看一下,如图2
图2
我们发现实际上\0也是被拷贝过来了的。

函数的模拟实现

我们来写一个函数my_strcpy实现字符串的拷贝,框架如下

void my_strcpy(char* dest, char* src)
{

}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

图3

当’\0’也被拷贝过去时函数停止运行,我们可以用一个循环来实现代码

void my_strcpy(char* dest, char* src)
{
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}//当src解引用为'\0'时跳出循环,但'\0'还并没有被复制过去
	*dest = *src;//将最后的'\0'也复制过去
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

代码优化

上述函数只是我们按照基本思路一步步写出来的,肯定不是最优解,看下面这段代码

void my_strcpy(char* dest, char* src)
{
	while (*dest++=*src++)
	{
		;
	}
}

这段代码才是大师级别的书写格式,它将我们上述的个步骤融为一体,下面我们来分析这段代码。
首先我们将解引用的src的值赋给dest,然后后置++,各自都跳到下一个位置再进行赋值,当最后一次src解引用为’\0’并赋值给dest时,由于’\0’的ascll码值为0,当0被赋值给dest,判断结果也为0,0为假,就会跳出循环,这样既把\0复制了过去,还借此跳出了循环,可谓是一举两得。

assert–断言

假设arr1或arr2为空指针会发生什么呢?显然,空指针是不能解引用的,程序会报错。可是这种情况也是难以避免的,为了避免程序崩溃,我们在函数开头添加一个assert(断言),通过一个判断来选择继续执行或中止代码。

void my_strcpy(char* dest, char* src)
{
	assert(src != NULL);//若为真则继续执行,若为假则终止代码
	while (*dest++=*src++)
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1,NULL);
	printf("%s\n", arr1);
	return 0;
}

我们假定arr2为空指针,代码运行结果就会如下
图4
这样,我们既可以有效防止程序崩溃,还可以很清晰的在代码中锁定出问题的地方(比如途中出问题的地方就为源.c line27)。

const关键字

如果我们在函数书写中把拷贝对象和被拷贝对象写反了,会发生什么呢?

void my_strcpy(char* dest, char* src)
{
	assert(src != NULL);
	while (*src++=*dest++)
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1,arr2);
	printf("%s\n", arr1);
	return 0;
}

代码运行结果如图5
图5
我们会发现程序崩溃了,原因在于arr2字符串长度放不下arr1。但如果我们加入const关键字修饰就能很好的规避这个问题。

const关键字的作用在于修饰变量,这个变量就被称为常变量,它具备了常量的属性,但本质上还是一个变量。
但我们来看一段代码

int main()
{
    const int num = 10;
	int* p = &num;
	*p = 20;

	printf("%d\n",num);
}

运行结果如图6
图6
我们发现,被const修饰的变量num还是被修改了,我么要想保持num不变,就需要修饰指针变量

int main()
{
    int num = 10;
	const int* p = &num;
	*p = 20;

	printf("%d\n",num);
}

这样* p=20这段代码将无法实行。这是因为const如果放在* 左边,修饰的是*p,表示的是指针指向的内容,是不能通过指针来改变的,但是指针变量本身( p )是可以修改的,如果放在 *右边,修饰的就是p,和放在左边完全相反,指针变量本身将无法被修改,但指针指向的内容却可以被修改,num还是会被修改为20

strcpy的返回值

strcpy这个库函数的执行原理实际上是会返回目标空间的起始地址

char* my_strcpy(char* dest, const char* src)
{
	assert(src != NULL);
	assert(dest != NULL);
	char* ret = dest;
	while (*dest++=*src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	//目标空间的起始地址 源空间的起始地址
	my_strcpy(arr1,arr2);
	printf("%s\n", my_strcpy(arr1,arr2);//链式访问
	return 0;
}

结语

以上就是标准的库函数strcpy的模拟实现流程,如有出入,欢迎指正。

相关文章:

  • Python爬虫以及数据可视化分析之某站热搜排行榜信息爬取分析
  • stream操作常用API 示例详解
  • GitHub2022年十大热门编程语言榜单
  • 利用STC15输出两路互补SPWM波形
  • 我发现买不起自己出版的书了,这到底是咋回事?
  • 「自定义类型」C语言中的构造数据类型如结构,联合,枚举
  • 【C++修炼之路】C++入门(下)
  • 【C++】C++11语法 ~ 可变参数模板
  • 初识计算机网络
  • 无痕埋点在Android中的实现
  • 全网最详细地介绍mybatis-plus框架
  • C语言及算法设计课程实验五:循环结构程序设计
  • Java 定时任务详解
  • h5实现相机
  • 字节跳动青训营--前端day6
  • 「面试题」如何实现一个圣杯布局?
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • Java 多线程编程之:notify 和 wait 用法
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • js学习笔记
  • Linux Process Manage
  • Linux后台研发超实用命令总结
  • php面试题 汇集2
  • Python中eval与exec的使用及区别
  • ReactNativeweexDeviceOne对比
  • 服务器从安装到部署全过程(二)
  • 诡异!React stopPropagation失灵
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 线上 python http server profile 实践
  • 项目实战-Api的解决方案
  • 原生Ajax
  • 转载:[译] 内容加速黑科技趣谈
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • ​低代码平台的核心价值与优势
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #if 1...#endif
  • #宝哥教你#查看jquery绑定的事件函数
  • (14)Hive调优——合并小文件
  • (2015)JS ES6 必知的十个 特性
  • (30)数组元素和与数字和的绝对差
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (转)ObjectiveC 深浅拷贝学习
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET : 在VS2008中计算代码度量值
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • ??javascript里的变量问题
  • [ Linux ] Linux信号概述 信号的产生
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • [.NET]桃源网络硬盘 v7.4