字符串函数剖析(3)---strstr函数

article/2025/8/22 5:22:05

1.strstr函数的巧妙 – 查找子字符串

1.1模拟实现strstr函数

strstr函数:在一个字符串中查找子串

学习新函数时,先去c库查找该函数的相关资料,更加助于你的学习

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

先看函数的声明,
参数是两个地址,不可更改。
先看看strstr函数的用法:
假如有一个字符串p1 = “abcdef” ,另一个字符串 p2 =“cde”,在p1中查找p2,肉眼可见,p1中确实存在p2,用代码来展示一下:

int main()
{char p1[] = "abcdef"char p2[] = "cde";char *ret = strstr(p1, p2);if (ret == NULL){printf("%s\n", "找不到");}else{printf("%s\n", ret);}
}

在这里插入图片描述
可以看到,打印出了cdef,来看一下库函数的解释:
在这里插入图片描述
它的意思是,如果字符串1中不存在字符串2,则返回 NULL,否则,返回字符串1中出现字符串2的首次出现的地址。在上面 “abcdef” 和 "cde"的例子中,返回值则为c的地址,打印出来的话,就会顺着c的地址往下打印。

那假如 是这样的例子呢?
p1 = “abcdebcde” , p2 = “cde”,

在这里插入图片描述
很明显,由库函数的返回值可知,返回的是第一次出现这个串时的地址。

下面来模拟实现my_strstr函数:

模拟实现strstr函数

在模拟实现该函数之前,我们先看一个例子,看懂这个例子,你才能看懂模拟实现的过程。

假设有一字符串:p1 = “abbbcde” , p2 = “bbc”,则在 p1 中查找 p2,很明显,肉眼可以知道,的确存在。
当我们去写代码时:,先看下图:

在这里插入图片描述
,p1 所指向的位置!= p2,所以 p1 后移一位,移动到b,此时 p1 == p2,继续后移,直到p2 指向c,p1 指向第三个b时,
在这里插入图片描述
此时p1 != p2,则需要将p2回溯到最开始的位置p1也从最开始的位置的后一位开始查找,如下图:

在这里插入图片描述
但遗憾的是,没人记住p1 和 p2的最开始的位置,p1 和p2 一旦移动了,就不好找回原来的位置了,所以定义两个临时变量指向 p1和p2的位置,
在这里插入图片描述
此时我们只需要移动s1和s2即可,p1和p2保持不变,回到刚刚上面的那句加粗的话:
p2回溯到最开始的位置p1也从最开始的位置的后一位开始查找,这个任务就交给s1和s2来做就行,我们继续往下走:此时s1与s2所指向的第一个和第二个位置都匹配了,但是当s2指向c,s1指向第三个b时,不相同,则 s2 又回溯到p2 的位置,s1回溯到p1的 后两位,这里又出现了一个问题, p1一动不动在a这个位置,怎么知道p1的后两位是哪一个字母呢?,这又需要引入另一个变量 :cur
在这里插入图片描述
当我们的s1每次回溯时,cur都会往下走一位,说明没有匹配到子串。
这是p1 在每次移动时的过程:在这里插入图片描述
在这里插入图片描述
这是p2在每次移动时的过程

当每一次匹配不成功时,cur会跳转到下一位,继续匹配
看到这里,如果你明白了,那就大功告成了。

char* my_strstr(const char* p1, const char* p2)
{assert(p1 && p2);char* s1 = NULL;char* s2 = NULL;char* cur = (char*)p1; NUL和Null都是 '\0'if (*p2 == '\0'){return (char*)p1;}while (*cur){                 abbbcdefbbcs1 = cur;s2 = (char*)p2;while (s1 && s2 && (*s1 == *s2)){s1++;s2++;}if (*s2 == '\0'){return cur; //找到了}if (*s1 == '\0'){return NULL;//找不到} 相当于找完了p1串都找不到,跳出cur的循环,这里如果多写一层,就画蛇添足了cur++;}return NULL; 找完了p1都找不到}

重点部分再次详细介绍。
在这里插入图片描述
结果如上:
总结:重点是理解 ”abbbcdef“ 和”bbc“这个例子就大功告成了在这里插入图片描述


http://chatgpt.dhexx.cn/article/QIJCxBRR.shtml

相关文章

C语言strstr()函数用法-字符串查找

1.函数定义 strstr()函数是一个参数为两个字符指针类型,返回值是char*类型的函数。 用于找到子串(str2)在一个字符串(str1)中第一次出现的位置(不包括str2的串结束符),并返回该位置…

ConcurrentHashMap 实现原理

一. ConcurrentHashMap 是什么 在并发编程中,ConcurrentHashMap 是一个经常被使用的数据结构,相比于 Hashtable 以及Collections.synchronizedMap() 来说,ConcurrentHashMap 在线程安全的基础上提供了更好的写并发能力,同时还降低…

ConcurrentHashMap 详解

前言 ConcurrentHashMap。 以下的技术点都基于JDK1.8~ 基础回顾 我们都知道,从JDK1.8起,ConcurrentHashMap底层的数据结构就已经从原来的Segment分段锁变为了数组 链表 红黑树的形态。 它是一款并发容器,一款装数据的容器在并发环境下铁…

ConcurrentHashMap介绍

引言 学习ConcurrentHashMap,合理的问题顺序应该如下: ConcurrentHashMap是什么(WHAT)为什么要有ConcurrentHashMap(WHY)ConcurrentHashMap的实现原理(HOW)ConcurrentHashMap如何使…

一文彻底弄懂ConcurrentHashMap

一文彻底弄懂ConcurrentHashMap 导读前言锁synchronizedvolatile(非锁)自旋锁分段锁ReentrantLockCAS ConcurrentHashMap 实现原理JDK1.7 中的 ConcurrentHashMapSegmentConcurrentHashMap 并发读写的几种情况get 方法put 方法 JDK1.8 中的 ConcurrentHa…

ConcurrentHashMap杂谈

为什么使用ConcurrentHashMap 在并发编程中使用HashMap可能导致程序死循环,而使用线程安全的HashTable效率又非常低下 线程不安全的HashMap 在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100% 死循环案例&#xf…

图解ConcurrentHashMap

曾经研究过jkd1.5新特性,其中ConcurrentHashMap就是其中之一,其特点:效率比Hashtable高,并发性比hashmap好。结合了两者的特点。 集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据结构的支…

Java集合:ConcurrentHashMap

本篇内容包括:ConcurrentHashMap 概述、ConcurrentHashMap 底层数据结构、ConcurrentHashMap 的使用以及相关知识点。 一、ConcurrentHashMap 概述 ConcurrentHashMap 是 HashMap 的线程安全版本,其内部和 HashMap 一样,也是采用了数组 链表…

Hashtable与ConcurrentHashMap区别

ConcurrentHashMap融合了hashtable和hashmap二者的优势。 hashtable是做了同步的,hashmap未考虑同步。所以hashmap在单线程情况下效率较高。hashtable在的多线程情况下,同步操作能保证程序执行的正确性。 但是hashtable每次同步执行的时候都要锁住整个结…

ConcurrentHashMap 面试题

作者:程序员库森 链接:https://www.nowcoder.com/discuss/591527?source_idprofile_create_nctrack&channel-1 来源:牛客网 本文汇总了常考的 ConcurrentHashMap 面试题,面试 ConcurrentHashMap,看这一篇就够了…

Hashmap和ConcurrentHashmap的区别

HashTable (1)底层数组链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化 (2&#xff0…

ConcurrentHashMap的作用与用法

ConcurrentHashMap的作用与用法 一.ConcurrentHashMap简介 ConcurrentHashMap是属于JUC工具包中的并发容器之一,在多线程开发中很经常会使用到这个类,它与HashMap的区别是HashMap是线程不安全的,在高并发的情况下,使用HashMap进行…

Java并发包concurrent——ConcurrentHashMap

目录 1. ConcurrentHashMap的实现——JDK7版本 1.1 分段锁机制 1.2 ConcurrentHashMap的数据结构 1.3 ConcurrentHashMap的初始化 1.3.1 初始化ConcurrentHashMap 1.3.2 初始化Segment分段 1.4 定位Segment 1.5 ConcurrentHashMap的操作 1.5.1 get 1.5.2 put 1.5.3 …

Java8 ConcurrentHashMap详解

点个赞,看一看,好习惯!本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了 3 个月总结的一线大厂 Java 面试总结,本人已拿大厂 offer。 另外,原创文章首发在我的个人博客&#x…

HashMap与ConcurrentHashMap的区别

从JDK1.2起,就有了HashMap,正如前一篇文章所说,HashMap不是线程安全的,因此多线程操作时需要格外小心。 在JDK1.5中,伟大的Doug Lea给我们带来了concurrent包,从此Map也有安全的了。 ConcurrentHashMap具体…

concurrenthashmap实现原理

1.JDK 1.7 ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成 Segment 继承自 ReentrantLock&#xff0c;是一种可重入锁&#xff1b;其中&#xff0c;HashEntry 是用于真正存储数据的地方 static final class Segment<K,V> extends ReentrantLock i…

HashMap和ConcurrentHashMap

前言 Map 这样的 Key Value 在软件开发中是非常经典的结构&#xff0c;常用于在内存中存放数据。 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器&#xff0c;在正式开始之前我觉得有必要谈谈 HashMap&#xff0c;没有它就不会有后面的 ConcurrentHashMap。 Hash 表 在…

深入浅出ConcurrentHashMap详解

文章目录 1、前言2、什么是ConcurrentHashMap3、Put 操作4、Get 操作5、高并发线程安全6、JDK8 的改进6.1 结构改变6.2 HashEntry 改为 Node6.3 Put 操作的变化6.4 Get 操作的变化6.5 总结 1、前言 学习本章之前&#xff0c;先学习&#xff1a;深入浅出HashMap详解&#xff08;…

ConcurrentHashMap

ConcurrentHashMap 1.ConcurrentHashMap的出现 我们最常用的集合框架一定包括HashMap&#xff0c;但是都知道它不是线程安全的。在并发插入元素的时候&#xff0c;有可能出现带环链表&#xff0c;让下一次读操作出现死循环。 而想要次避免HashMap的线程安全问题有很多办法&am…

ConcurrentHashMap详解

文章目录 什么是ConcurrentHashMapConcurrentHashMap结构如何高效的执行并发操作如何进行锁的选择Node节点类型与作用扩容的方式 源码分析putVal()方法spread()方法&#xff0c;获取槽位。initTable()方法&#xff0c;初始化容器addCount() &#xff0c;计算成员数量transfer()…