【C语言】strstr函数的使用和模拟

前言

今天给大家带来一个字符串函数,strstr()的使用介绍和模拟实现。

模拟实现这个函数,可以帮助我们更深刻地理解这个函数的功能和提高解决字符串相关问题的能力,有兴趣的话就请往下看吧。

strstr函数介绍

函数功能:

strstr函数的功能是在字符串中找另一个字符串有无出现,或者说就是找一个子字符串。如果能找到,就返回第一次出现的地址,如果找不到就返回空指针。

函数原型:

const char* strstr(const char* str1,const char* str2);或char* strtstr(char* str1,const char* str2);

可以看到,我们从函数外部接收两个字符指针,它们各自指向一个字符串的首元素地址,一个字符串是被寻找的字符串,另一个就是要找的子字符串。两个字符指针都用const修饰,因为我们不期望在这个函数中去修改字符串的内容。返回的是一个字符指针,也就是第一次出现的地址或者空指针,同样可以用const进行修饰。

需要的头文件:
#include<string.h>

函数使用:

现在,我们写个代码来看一下这个函数具体是如何使用的:

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "abcdefabcdef";char* p = "efab";char* ret = strstr(arr, p);//创建一个指针接收第一次出现的地址或空指针printf("%s\n", ret);//打印看看结果return 0;
}

在字符串“abcdefabcdef”中寻找“efab”是否出现过,很明显是出现过的,所以这时我们应该返回其第一次出现的位置,也就是字符'e'的位置。当我们用printf("%s\n", ret);将其打印,应该得到的就是“efabcdef”,因为打印会到‘\0’才停下。

vs运行效果:

可以看到,确实是这个效果。那么strstr的使用大致就是这样。

strstr函数的模拟实现

那么,现在我们能否自己写出一个函数来模拟实现库函数strstr的功能呢?当然是可以的,不过要注意将问题分析全面。

分析:

不妨就将我们自己写的strstr函数命名为my_strstr,我们可以先根据strstr的原型,模拟写出my_strstr的原型: 

const char* my_strstr(const char* str1,const char* str2)
{//
}

在上面使用strstr的代码中我们可以看到函数调用部分为char* ret = strstr(arr, p);所以由此我们可以看出应该怎么写相应的my_strstr的原型。

参数部分,因为我们要接受两个字符串,在前者中找后者,因为不期望这两个固定的字符串被修改,所以可以用const进行修饰,而返回值就是如果找到后的第一次出现的地址,也可以用const进行修饰。 

接下来,在开始找之前,我们应该再创建两个字符指针变量并分别用str1和str2对其赋值,也就是复制一对str1、str2,为什么这么做呢?因为当我们移动str1与str2,遇到匹配失败,需要让str2回到起点,str1回到某个位置时,我们已经找不到原来str1和str2指向的位置了,所以我们需要让str1与str2始终指向原本的位置,去移动复制的str1和str2。(等往下说,看到str2回到起点和str1回到某个位置的情况时,可能会更好理解)

假设此时我们的str1和s1指向“abcdefabcdef”(末尾有个隐藏的'\0'),str2和s2指向“cdef”(末尾有个隐藏的),以下是我们这个函数大致的实现逻辑:

首先我们得在str1(简约说法)中找到‘c’,因为如果连‘c’都找不到,那就是直接找不到了。找到‘c’之后就让s1和s2继续往后走进行匹配。

因为s1和s2在这个过程中会向后走,所以当我们最初在s1指向字符串中成功找到‘c’的时候要做一件事情,把当前str1中'c'的位置记录下来,因为这说明从这里开始向后是有可能匹配成功的(也就是说这可能就是我们最终要返回的值),而如果不记录下来最后我们找不回来这个位置。所以我们可以创建一个指针cur进行记录。

然后,假设确实能顺利在str1中找到str2,我们在s1和s2不断向后走的过程中,s2就会遇到‘\0’,这时就意味着匹配成功,我们只需将cur(子字符串第一次出现地址)返回就行了。

复杂情况:

但是往往情况没有那么顺利,我们需要探讨非一次匹配成功的情况,让我们的代码能够应对。

很有可能出现也比较难理解的就是多次匹配的情况

多次匹配是什么意思呢?

现在来举个例子,假设现在我们被找的字符串变为“abbbcdef”(末尾隐藏‘\0’),要找的子字符串变为“bbc”(末尾隐藏‘\0’),那么就会在s2走到‘c’的时候遇到s1不为‘c’的情况,这一次的匹配就失败了。

但是,这时的匹配失败并不代表就是在s1中找不到s2(可以看出来是找得到的),所以我们不能在一次匹配失败后就返回空指针,而是应该让cur往后走一步,让s2回到起点,s1回到cur的位置, 再重新进行匹配:

每次匹配失败我们就将cur向后移动一位,当cur遇到‘\0’的时候,就说明真的找不到了。

还有一种可能就是在某一次s1与s2往后走的时候s1提前遇到了‘\0’,这说明s1的长度已不可能出现完整的str2,可以提前返回空指针。

my_strstr完整代码参考

在分析过各种情况后,我们就能写出strstr函数的模拟实现的代码了:

vs2022运行效果:

到此,strstr函数的使用以及模拟实现的讲解就结束了,如遇到文中错误,可以向我指正。 

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

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

相关文章

synchronized什么情况下会释放锁?

synchronized关键字可以用于实现线程之间的同步&#xff0c;它可以修饰方法或代码块&#xff0c;保证在同一时间只有一个线程能够访问被synchronized修饰的代码。 synchronized会在以下情况下释放锁&#xff1a; 代码块执行完毕&#xff1a; 当一个线程执行完了一个被synchro…

Three.js 研究:3、创建一个高科技圆环

打开Alpha混合 修改环形颜色&#xff0c;更改发光的颜色&#xff0c;更改发光的强度为2 更改世界环境灯光

使用 Docker Compose 接管现有容器的文档

前言 在使用 Docker 容器技术时&#xff0c;有时我们可能需要 Docker Compose 来接管并管理已经存在的容器。这通常发生在容器手动启动或由其他部署流程创建后&#xff0c;我们希望利用 Docker Compose 来简化未来的管理任务。 准备工作 在尝试接管现有容器之前&#xff0c;…

如何编辑 PDF 中的文本?4个有效的编辑PDF方法

PDF 文件可以轻松打开和查看&#xff0c;但修改要复杂得多 - 尤其是在 PDF 中的文本编辑方面。 知道如何离线编辑 PDF 中的文本对于任何需要快速更改而无需在线加载文档或担心安全问题的人来说都非常有益。它使用户能够更好地控制他们的文档&#xff0c;并有更广泛的字体和图形…

着急联系媒体投稿发表文章有什么好方法?

作为一名曾经的信息宣传员,我深知在紧张的宣传节点上,急于将精心撰写的文章推向更广阔的读者群体,那种紧迫感和焦虑几乎成了常态。记得那段时间,为了能让稿件得到及时有效的曝光,我不得不亲自踏上了一场寻找媒体联系方式的“马拉松”。那时,我手头的资源有限,仅有的几个联系方式…

JRT1.7发布

JRT1.7连仪器在线演示视频 JRT1.5实现质控主体、1.6基本完成质控&#xff1b;本次版本推进到1.7&#xff0c;1.7集菜单权限、登录、打印导出客户端、初始化、质控、Linux客户端、仪器连接和监控体系各种功能大全&#xff0c;上十年写系统用到的都全了。 这次直接挑战检验最难…

就业信息|基于SprinBoot+vue的就业信息管理系统(源码+数据库+文档)

就业信息管理系统 目录 基于SprinBootvue的就业信息管理系统 一、前言 二、系统设计 三、系统功能设计 1前台功能模块 2后台功能模块 4.2.1管理员功能 4.2.2学生功能 4.2.3企业功能 4.2.4导师功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设…

Python3 笔记:模块的导入方式

1、import import 模块名 2、import as import a as b import as的方式其实是实现了两步操作&#xff1a;先将模块导入&#xff0c;再为模块重命名。 3、from import from a import func from import方式是直接导入模块内的函数。 from import *方式将模块中所有的名字…

算法学习-构造

文章目录 相关题目667.优美的排列II481.神奇字符串 构造题会让我们按照一定的规律去构造一个符合条件的结果&#xff0c;其通常是和其他算法结合起来考察的&#xff0c;其中的规律有时候是比较难找的&#xff0c;因此只能对其进行规律总结。 相关题目 667.优美的排列II 参考…

MySql基础(一)--最详细基础入门,看完就懂啦(辛苦整理,想要宝宝的赞和关注嘻嘻)

前言 希望你向太阳一样&#xff0c;有起有落&#xff0c;不失光彩~ 一、数据库概述 1. 什么是数据库 数据库就是存储数据的仓库&#xff0c;其本质是一个文件系统&#xff0c;数据按照特定的格式将数据存储起来&#xff0c;用户可以对数据库中的数据进行增加&#xff0c;修改&…

大白话DC3算法

DC3算法是什么 DC3算法&#xff08;也称为Skew算法&#xff09;是一种高效的构建后缀数组的算法&#xff0c;全称为Difference Cover Modulo 3算法。 该算法于2002年被提出&#xff0c;论文参考&#xff1a; https://www.cs.cmu.edu/~guyb/paralg/papers/KarkkainenSanders0…

Vue3:封装Table 表格组件

组件官网 elementPlus : 点击跳转 封装组件 创建新的组件文件: Table.vue <!-- PropTableS &#xff1a; 父组件传递过来的数据 (对象)PropTableS.tables : 父组件传递的对象中 存放表格每行显示的数据PropTableS.keyS &#xff1a; 父组件传递过来的对象&#xff0c;里…

docker搭建私有仓库并推送本地镜像

1、私仓搭建 docker pull registry#拉取镜像 docker images#查看镜像 mkdir -p /czx/myregistry 创建挂载目录 运行私有库registry (相当于本地有个是有docker hub) docker run -d -p 5000:5000 -v /czx/myregistry/:/tmp/registry --restartalways --privilegedtrue regist…

STM32 USART的字符编码(发送器的实现逻辑)

目录 概述 1 字符编码 1.1 USART 字符说明 1.2 字长编程 2 发送器 2.1 字符发送 2.2 可配置的停止位 2.3 配置停止位方法 3 单字节通信 4 中断字符 5 空闲字符 概述 本文主要讲述STM32 USART的发送端功能实现的原理&#xff0c;包括字节编码长度&#xff0c;发送器…

MOS选型及其参数解析

背景&#xff1a; 整理现有常用元器件选型&#xff0c;日后使用时针对性观看&#xff0c;生成列表链接如下&#xff1a; https://blog.csdn.net/caozhaokun/article/details/126069701 作者&#xff1a;Cayden 时间&#xff1a;2024/05/26 一、MOS选用现状 MOS是电路设计…

【JavaEE初阶】HTTP协议|HTTP请求|URL基本格式|URLencode

&#x1f4a1;推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳转到网站】 HTTP请求(Request) 认识URL URL基本格式 平时我们俗称的"⽹址"其实就是说的URL(Uniform Resource Loc…

MySQL--备份恢复

目录 一、备份恢复的工作职责 1.备份的时间周期 2.备份的方式 3.恢复方案 4.检查备份 5.定期恢复演练 6.故障恢复策略 7.迁移升级 二、逻辑备份工具--mysqldump 1.介绍 2.使用场景 3.mysqldump命令的参数介绍 1&#xff09;全备&#xff1a; 2&#xff09;单库或…

YOLO 学习和使用 (重拾机器学习)

contents a nenrons 单层神经网络 多层神经网络 CNN (Convolutional Neural Network) YOLO 5.1. YOLO(you only look once) 5.2. predict stage: 置信度 * 类别条件概率 全概率非极大值抑制&#xff0c;通过IOU 指数进行实现每个 grid cell 生成两个预测 bounding box 无…

Java 注解和反射

文章目录 1. 注解 - annotation1.1 什么是注解1.2 内置注解1.3 元注解&#xff08;meta-annotation&#xff09;1.4 自定义注解 2. 反射2.1 反射机制概述2.2 Class 类2.3 获取 Class 类的实例2.4 所有类型的 Class 对象2.5 类的加载与 ClassLoader 的理解2.6 什么时候会发生类的…

dsPIC单片机buck-boost拓扑双向DC-DC电源变换器设计

为实现电池储能装置的双向DC-DC变换器&#xff0c;本系统以buck-boost拓扑电路为核心&#xff0c;通过DSPICFJ256GP710单片机最小系统控制拓扑的切换&#xff0c;从而进行buck恒流充电和boost恒压放电。充电时效率≥94%&#xff0c;放电时效率≥95.5%&#xff0c;具有过压保护及…