模拟实现字符串库函数(一)

news2024/9/28 1:25:19

在C语言的标准库中提供了很多针对字符串的库函数,这篇文章我们会学习并模拟实现几个简单的库函数

求字符串长度函数strlen

strlen函数我们在之前已经用过很多次了,同时也模拟实现过,但是都不是模仿标准库中的strlen来实现,首先我们在cplusplus中找到strlen函数的介绍

从介绍中我们知道strlen的返回值是一个size_t的无符号整型,参数是一个const修饰的字符指针。而strlen的功能是求字符串的长度,他以'\0'为结束标志,返回的是 '\0' 之前的字符个数。当我们传过去的字符串内容没有 '\0' ,strlen函数会一直向后访问知道找到 '\0' 。所以我们在使用strlen函数时一定要确定字符串结尾有结束标志。

strlen的模拟实现代码如下:

size_t my_strlen(const char* str)
{
    assert(str);
	if (*str != '\0')
	{
		return 1 + my_strlen(str + 1);
	}
	else
	{
		return 0;
	}
}

长度不受限制的字符串函数

strcpy

strcpy的两个参数分别是char* destination 要拷贝的目标地址,char* source 拷贝的源头,返回的是目标地址,不过这个函数我们在使用时一般不会用一个指针来接收返回值。 这个函数的特点就是遇到 '\0' 结束,拷贝的是 '\0' 及以前的字符。如果source传过来的字符串中没有 '\0' ,这个函数就会一直向后访问拷贝,直到遇到 '\0' ,与strlen类似,所以我们在使用这个函数时要做好参数的设置。

使用的时候要注意的是,要拷贝的字符串一定要有结束标志,目标空间一定要足够,目标空间一定要可修改,不能传const修饰的或者常量的指针。同时要注意不要更改source的内容。

char* my_strcpy(char* dest, const char* source)
{
    assert(dest&&source);
    char* ret=dest;
	while (*dest++=*source++)
	{
		;
	}
}

strcat

strcat是一个字符串追加函数,两个参数 destination和source分别是被追加的字符串起始地址和追加的字符串的地址,要注意目标空间一定要足够放得下追加后的字符串,同时目标空间一定要可修改。 

模拟实现这个函数的第一步便是要找到destination中字符串的结尾,然后从这个位置开始追加,追加后会补一个'\0',可以理解为把source字符串的'\0'也追加上去了。

char* my_strcat(char* dest, const char* source)
{
	assert(dest && source);
	char* ret = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (*dest++ = *source++)
	{
		;
	}
}

在我们实现的这个函数是没办法实现自己给自己追加(dest和source有重叠部分),因为追加的时候覆盖原字符串,导致'\0'也会被覆盖,死循环。

strcmp

strcmp函数是一个字符串比较函数,两个参数是要比较的两个字符串。如果第一个字符串小于第二个字符串,就返回小于0的整型,如果两个字符串内容相等则返回0,否则返回大于0的整型。这个函数是逐字符比较,比较的是两个字符的ASCII码值。在使用时也要注意检查参数有没有结束标志。

int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2&&*s1!='\0')
	{
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

长度受限制的字符串函数

strncpy

strncpy相对于strcpy多了一个num参数,表示要拷贝的字符个数,拷贝完之后会补一个'\0',要注意num不要大于source的长度,当num大于source长度时会用'\0'来补充。

char* my_strncpy(char* dest, const char* source,size_t num)
{
	assert(dest && source);
	char* ret = dest;
	while (*source!='\0'&&num--)
	{
		*dest = *source;
		dest++;
		source++;
	}
	if (num > 0)
	{
		while (num--)
		{
			*dest++ = '\0';
		}
	}
	*dest = '\0';
	return ret;
}

strncat

与strcat相比多了一个num参数,表示要追加的字符,注意事项一样,同时,strcat再追加完num个字符后会在后面补一个'\0'。num长度不能大于source长度。

char* my_strncat(char* dest, const char* source, size_t num)
{
	assert(dest, source);
	char* ret = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (num--)
	{
		*dest++ = *source++;
	}
	*dest = '\0';
	return ret;
}

strncmp

比较两个字符串前num个字符的大小。

int my_strncmp(const char* s1, const char* s2, size_t num)
{
	assert(s1 &&s2);
	while (*s1 == *s2 &&num--)
	{
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

查找子串函数strstr

可以看到这个函数有两个参数,作用是再str1中查找是否有字串str2,如果有,返回str1中字串的起始地址,如果没有字串,返回空指针。

这个函数模拟实现的思路就是遍历str1,如果有字符与str2首字符相同,则比较是不是字串。要注意的是,遍历str1时要用两个指针,一个用来遍历str1并在比较时记录当前位置,一个用来判断是不是字串。

char* my_strstr(const char* s1, const char* s2)
{
	assert(s1 && s2);
	char* begin = s1;
	char* cmp1 = begin;
	char* cmp2 = s2;
	while (*begin != '\0')
	{
		if (*begin == *s2)
		{
			cmp1 = begin;
			cmp2 = s2;
			while (*cmp2 != '\0'&&*cmp1==*cmp2)
			{
				cmp1++;
				cmp2++;
			}
			if (*cmp2 == '\0')//匹配成功
			{
				return begin;
			}
		}
		begin++;
	}
	//前面没有返回就意味着找不到子串
	return NULL;
}

切割字符串函数strtok

这个函数两个参数,str是要切割的字符,delimiters是个字符串,定义了用作分隔符的字符集合。这个函数的作用就是str中遇到delimiters中的字符就标记,把这个标记改成'\0',并返回这一子字符串的地址,同时strtok会保存这个标记的下一个位置,如果下一次使用strtok函数时第一个参数传的是NULL,strtok就会从这个位置开始继续查找下一个标记。当我们传的字符串中有多个分隔符,我们只需要第一次调用strtok时传字符串,之后调用就传NULL来找第二个标记。如果字符串结束都没找到标记,就返回空指针。

我们在模拟实现的时候要注意用static修饰保留上一次查找到的地址。

如果两个分隔符连在一起,就跳过这些连在一起的分隔符,因为这两个分隔符之间没有元素。

char* my_strtok(char* str, const char* sep)
{
	assert(sep);
	char* s2 = sep;
	static char* begin ;

	if (str != NULL)
	{
		begin = str;
	}
	if (*begin == '\0')//遍历完了str,返回空指针
	{
			return NULL;
	}

	

	char* s1 = begin;
	while (*s1 != '\0')//跳过字符串开始的分隔符
	{
		int flag = 0;
		s2 = sep;
		while (*s2 != '\0')
		{

			if (*s1 == *s2)
			{
				flag = 1;
				*s1 = '\0';
				begin++;
				break;
			}
			s2++;
		}
		if (flag == 0)
		{
			break;
		}
		else
		{
			s1++;
		}
	}
	//找分隔符
	while (*s1 != '\0')
	{
		s2 = sep;
		int flag = 0;
		while (*s2 != '\0')
		{
			if (*s2 == *s1)
			{
				flag = 1;
				break;
			}
			s2++;
		}
		if (flag == 1)
		{
			*s1 = '\0';
			char* ret = begin;
			begin = s1+1;
			return ret;
		}
		else
		{
			s1++;
		}
	}
	//str遍历结束返回后面的字符
	char* ret = begin;
	begin = s1;
	return ret;
	
}

这段代码可能有点难理解,主要是begin指针的操作有点复杂。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1541728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【现代C++】可变参数模板

现代C中的可变参数模板是C11引入的一个功能&#xff0c;允许模板接受可变数量的参数&#xff0c;使得模板编程更加灵活和强大。 1. 基本用法 可变参数模板允许您创建接受任意数量参数的函数或类模板。 template<typename... Args> void func(Args... args) {// 处理参…

【Frida】【Android】01_手把手教你环境搭建

▒ 目录 ▒ &#x1f6eb; 导读开发环境 1️⃣ 环境搭建安装Android模拟器安装Frida CLI安装Frida Server端口重定向&#xff1a;adb forward 2️⃣ 运行测试spwan模式attach模式直接加载脚本 &#x1f4d6; 参考资料 &#x1f6eb; 导读 开发环境 版本号描述文章日期2024-03…

鸿蒙Harmony应用开发—ArkTS-类型定义

说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 Resource 资源引用类型&#xff0c;用于设置组件属性的值。 可以通过$r或者$rawfile创建Resource类型对象&#xff0c;不可以修改Res…

MySQL学习笔记------SQL(2)

ziduanSQL DML 全称为&#xff1a;Data Manipulation Language&#xff0c;用来对数据库中表的数据记录进行增删改操作 插入数据 添加数据&#xff08;INSERT&#xff09; 给指定字段添加数据&#xff1a;INSERT INTO 表名(字段名1&#xff0c;字段名2&#xff0c;......…

Gogs - 一款极易搭建的自助 Git 服务

Gogs - 一款极易搭建的自助 Git 服务 1. 使用文档References Gogs https://gogs.io/ https://github.com/gogs/gogs Gogs (/gɑgz/) 项目旨在打造一个以最简便的方式搭建简单、稳定和可扩展的自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发&#xff0c;并…

基于SSM的NEUQ宿舍管理系统的设计与实现

基于SSM的NEUQ宿舍管理系统的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全 获取源码——》公主号&#xff1a;计算机专业毕设大全

【计算机网络实践】Cisco Packet Tracer局域网组网(FTP服务器通过交换机连接客户端)

本文为应对计算机网络第一次实验所写的预习报告 一、实验准备 一台装有Cisco Packet Tracer的PC机&#xff0c;一个大学生大脑。 二、了解FTP和Cisco Packet Tracer 具体内容可在百度搜索&#xff0c;在物理机上用FileZilla Server实现ftp可参看我前面的文章。Cisco Packet Tr…

C#绘制面形图

创建windows窗体应用 ,从工具箱添加Button和Panel using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Fo…

再仔细品品Elasticsearch的向量检索

我在es一开始有向量检索&#xff0c;就开始关注这方面内容了。特别是在8.X之后的版本&#xff0c;更是如此。我也已经把它应用在亿级的生产环境中&#xff0c;用于多模态检索和语义检索&#xff0c;以及RAG相关。 也做过很多的优化&#xff1a;ES 8.x 向量检索性能测试 & 把…

Vue3 上手笔记

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

网络行为管理系统招标模板

项目名称&#xff1a;网络行为管理系统招标 一、项目背景 随着信息技术的迅猛发展&#xff0c;网络安全和数据保护已成为企业和组织面临的关键挑战。为了确保网络环境的安全、合规&#xff0c;并实现对网络行为的有效管理和审计&#xff0c;我们特此启动网络行为管理系统的招…

Linux系统下——PS1、PS2、PS3、PS4变量详解

目录 前言 一、PS1变量 1.PS1变量详解 2.PS1变量可用参数 3.彩色提示符 二、PS2变量 三、PS3变量 1.不使用PS3变量 2.使用PS3变量 四、PS4变量 前言 在Linux系统中&#xff0c;PS1、PS2、PS3和PS4是特定的环境变量&#xff0c;它们各自在控制提示符和菜单提示信息…

【算法每日一练]

目录 今日知识点&#xff1a; 辗转相减法化下三角求行列式 组合数动态规划打表 约数个数等于质因数的次方1的乘积 求一个模数 将n个不同的球放入r个不同的盒子&#xff1a;f[i][j]f[i-1][j-1]f[i-1][j]*j 将n个不同的球放入r个相同的盒子&#xff1a;a[i][j]a[i-j][j]a[…

[AIGC] Redis基础命令集详细介绍

Redis是一个强大的开源的键-值存储系统&#xff0c;被广泛应用于各种应用程序中。在使用Redis时&#xff0c;我们需要掌握一些基本的Redis命令来操作存储在其上的数据。这篇文章将向你介绍一些基本的Redis命令&#xff0c;让你能够更好地使用和理解Redis。 文章目录 启动Redis…

手撕算法-删除有序数组中的重复项

描述 很简单&#xff0c;就是&#xff0c;遇到重复的&#xff0c;只留一个&#xff0c;保存在数组的左半边。如&#xff1a;[0,0,1,1,1,2,2,3,3,4]变为[0,1,2,3,4] 分析 使用双指针。slow指针代表没重复的数应该放置的位置&#xff0c;fast表示遍历的不重复数字的位置&…

C++中,数字以0开头,会默认八进制,不是十进制

代码1 以下代码&#xff1a; #include <iostream>using namespace std;int main(){uint8_t a 0101;int b (int)(a);cout<<b<<endl;}结果输出&#xff1a; 代码2 如果改为&#xff1a; #include <iostream>using namespace std;int main(){uint8_…

【新版】系统架构设计师 - 新版架构备考索引<附2023年11月原题回忆>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 新版架构备考索引机考详情备考索引与方向&#xff08;个人观点&#xff0c;仅供参考&#xff09;总结附&#xff1a;2023年11月改版机试原题简单回忆 架构 - 新版架构备考索引 首先&#xff0c;此…

知识图表示学习中的负抽样研究综述

摘要 知识图表示学习(KGRL)或知识图嵌入(KGE)在知识构建和信息探索的人工智能应用中起着至关重要的作用。这些模型旨在将知识图中的实体和关系编码到低维向量空间中。在KGE模型的训练过程中&#xff0c;使用正样本和负样本是区分的必要条件。然而&#xff0c;直接从现有的知识…

Unity基础框架

公共模块 单例基类 如果有很多个这样的单例模式对象,创建他们时都要重复的写单例模式代码。那么能不能利用泛型来减少这部分重复的工作量呢。 单例模式基类,最简单的写法 继承MonoBehaviour的单例基类 所以需要做一些改进 获取单例时如果为空,创建一个名字一样的物体,挂…

如何在C语言中使用命令行参数

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…