【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函数的使用以及模拟实现的讲解就结束了,如遇到文中错误,可以向我指正。
相关文章:
【C语言】strstr函数的使用和模拟
前言 今天给大家带来一个字符串函数,strstr()的使用介绍和模拟实现。 模拟实现这个函数,可以帮助我们更深刻地理解这个函数的功能和提高解决字符串相关问题的能力,有兴趣的话就请往下看吧。 strstr函数介绍 函数功能: strstr函…...
五分钟”手撕“异常
目录 一、什么是异常 二、异常的体系和分类 三、异常的处理 1.抛出异常 2.异常的捕获 异常声明throws: try-catch处理 四、finally finally一定会被执行吗? 五、throw和throws区别 六、异常处理的流程 七、自定义异常 一、什么是异常 顾名…...
【vue3+elementuiplus】el-select下拉框会自动触发校验规则
场景:编辑弹框省份字段下拉框必填,触发方式change,有值第一次打开不会触发校验提示,关闭弹框再次打开触发必填校验提示,但是该字段有值 问题的原因是:在关闭弹层事件中,我做了resetfileds&…...
【论文复现】LSTM长短记忆网络
LSTM 前言网络架构总线遗忘门记忆门记忆细胞输出门 模型定义单个LSTM神经元的定义LSTM层内结构的定义 模型训练模型评估代码细节LSTM层单元的首尾的处理配置Tensorflow的GPU版本 前言 LSTM作为经典模型,可以用来做语言模型,实现类似于语言模型的功能&am…...
目标检测YOLO实战应用案例100讲-【自动驾驶】激光雷达
目录 前言 算法原理 测距方法 发射单元 接收单元 扫描单元...
用C语言设计轨道电机的驱动库
一、设计目的 设计能驱动立体轨道电机的抽象驱动程序库。 二、设计要求 命名规范。设计简单,方便使用。体积小。满足电机的移动、停止、初始化、恢复等控制,甚至通过网络控制。 三、设计内容 (一)属性封装 1、定义配置结构体 // 用于配置参数 typed…...
HTML跳动的爱心
目录 写在前面 HTML简介 跳动的爱心 代码分析 运行结果 推荐文章 写在后面 写在前面 哎呀,这是谁的小心心?跳得好快吖! HTML简介 老生常谈啦,咱们还是从HTML开始吧! HTML是超文本标记语言(Hyper…...
汇编原理(二)
寄存器:所有寄存器都是16位(0-15),可以存放两个字节 AX,BX,CX,DX存放一般性数据,称为通用寄存器 AX的逻辑结构。最大存放的数据为2的16次方减1。可分为AH和AL,兼容8位寄存器。 字:1word 2Byte…...
Android Studio开发之路(十三)主题影响Button颜色问题解决及button自定义样式
一、问题描述 在开发过程中发现安卓的默认主题色是紫色,并且会导致button也是紫色,有时直接在xml布局文件中直接设置button的背景色或者设置背景图片不起效果 方案一、如果是app,可以直接设置主题颜色 比如,将主题设置为白色&a…...
eNSP学习——OSPF单区域配置
目录 相关命令 实验背景 实验目的 实验步骤 实验拓扑 实验编址 实验步骤 1、基础配置 2、部署单区域OSPF网络 3、检查OSPF单区域的配置结果 OSPF——开放式最短路径优先 基于链路状态的协议,具有收敛快、路由无环、扩展性好等优点; 相关命令 […...
深度学习中的优化算法二(Pytorch 19)
一 梯度下降 尽管梯度下降(gradient descent)很少直接用于深度学习,但了解它是理解下一节 随机梯度下降算法 的关键。例如,由于学习率过大,优化问题可能会发散,这种现象早已在梯度下降中出现。同样地&…...
R实验 方差分析
实验目的: 掌握单因素方差分析的思想和方法; 掌握多重均值检验方法; 掌握多个总体的方差齐性检验; 掌握Kruskal-Wallis秩和检验的思想和方法; 掌握多重Wilcoxon秩和检验的思想和方法。 实验内容: &…...
AI智能体|手把手教你使用扣子Coze图像流的文生图功能
大家好,我是无界生长。 AI智能体|手把手教你使用扣子Coze图像流的文生图功能本文详细介绍了Coze平台的\x26quot;图像流\x26quot;功能中的\x26quot;文生图\x26quot;节点,包括创建图像流、编排文生图节点、节点参数配置,并通过案例…...
应用程序图标提取
文章目录 [toc]提取过程提取案例——提取7-zip应用程序的图标 提取过程 找到需要提取图标的应用程序的.exe文件 复制.exe文件到桌面,并将复制的.exe文件后缀改为.zip 使用解压工具7-zip解压.zip文件 在解压后的文件夹中,在.rsrc/ICON路径下的.ico文件…...
Excel表格在线解密:轻松解密密码,快速恢复数据
忘记了excel表格密码?教你简单两步走:具体步骤如下。首先,在百度搜索中键入“密码帝官网”。其次,点击“立即开始”,在用户中心上传表格文件即可找回密码。这种方法不用下载软件,操作简单易行,适…...
springboot小结1
什么是springboot Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。 简单来说,它提供了一堆依赖打包Starter,并已经按照使用习惯解决…...
【Qt 学习笔记】Qt窗口 | 菜单栏 | QMenuBar的使用及说明
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt窗口 | 菜单栏 | QMenuBar的使用及说明 文章编号:Qt 学习…...
Spark运行模式详解
Spark概述 Spark 可以在多种不同的运行模式下执行,每种模式都有其自身的特点和适用场景。 部署Spark集群大体上分为两种模式:单机模式与集群模式。大多数分布式框架都支持单机模式,方便开发者调试框架的运行环境。但是在生产环境中ÿ…...
vcpkg环境配置
vcpkg 使用linux相关库,设置环境变量VCPKG_ROOT,设置cmake工具链$VCPKG_ROOT/scripts\buildsystems\vcpkg.cmake set VCPKG_DEFAULT_TRIPLETx64-windows .\vcpkg.exe install fftw3 freetype gettext glibmm gtkmm libjpeg-turbo libpng libxmlpp libs…...
python学习:基础语句
目录 条件语句 循环语句 for 循环 while 循环 break continue 条件语句 Python提供了 if、elif、else 来进行逻辑判断。格式如下: Pythonif 判断条件1: 执行语句1... elif 判断条件2: 执行语句2... elif 判断条件3: 执行语句3... else: 执行语句4…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
