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

简介: strstr函数:在一个字符串中查找子串学习新函数时,先去c库查找该函数的相关资料,更加助于你的学习

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);
  }
}

e6ec5970f82e4e989a49143611963f5c.png

可以看到,打印出了cdef,来看一下库函数的解释:

e502001e58fb47bbbb8ac16864e2f4c0.png

它的意思是,如果字符串1中不存在字符串2,则返回 NULL,否则,返回字符串1中出现字符串2的首次出现的地址。在上面 “abcdef” 和 "cde"的例子中,返回值则为c的地址,打印出来的话,就会顺着c的地址往下打印。


那假如 是这样的例子呢?

p1 = “abcdebcde” , p2 = “cde”,

c9673ccbeb674faeb3062dafd5c67077.png

很明显,由库函数的返回值可知,返回的是第一次出现这个串时的地址。

下面来模拟实现my_strstr函数:

模拟实现strstr函数

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

假设有一字符串:p1 = “abbbcde” , p2 = “bbc”,则在 p1 中查找 p2,很明显,肉眼可以知道,的确存在。

当我们去写代码时:,先看下图:

b53cd34980694f3c99f826795147c44f.png

,p1 所指向的位置!= p2,所以 p1 后移一位,移动到b,此时 p1 == p2,继续后移,直到p0872b054f028471a9f3f788fab04628b.png2 指向c,p1 指向第三个b时,


此时p1 != p2,则需要将p2回溯到最开始的位置p1也从最开始的位置的后一位开始查找,如下图:

666434d4b9434d59b27f66952ea280e8.png

但遗憾的是,没人记住p1 和 p2的最开始的位置,p1 和p2 一旦移动了,就不好找回原来的位置了,所以定义两个临时变量指向 p1和p2的位置,

c078c00f5804411887e7c85abeda42de.png

此时我们只需要移动s1和s2即可,p1和p2保持不变,回到刚刚上面的那句加粗的话:

将p2回溯到最开始的位置,p1也从最开始的位置的后一位开始查找,这个任务就交给s1和s2来做就行,我们继续往下走:此时s1与s2所指向的第一个和第二个位置都匹配了,但是当s2指向c,s1指向第三个b时,不相同,则 s2 又回溯到p2 的位置,s1回溯到p1的 后两位,这里又出现了一个问题, p1一动不动在a这个位置,怎么知道p1的后两位是哪一个字母呢?,这又需要引入另一个变量 :cur

369c8a354dcb495c871ebf429d176798.png

当我们的s1每次回溯时,cur都会往下走一位,说明没有匹配到子串。

这是p1 在每次移动时的过程:


064eb8c73a7e4d92ba04fd838ee7eb0e.gif

6a5025b01f2c4cb2973e7d45a03139c6.gif

这是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)
  {                 abbbcdef
                  bbc
    s1 = 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都找不到
}

重点部分再次详细介绍。


e3b60ebf62424269b4accdd908a0869f.png

结果如上:

总结:重点是理解 ”abbbcdef“ 和”bbc“这个例子就大功告成了

相关文章
|
6月前
[字符串和内存函数]strcmp字符串函数的详解和模拟
[字符串和内存函数]strcmp字符串函数的详解和模拟
52 1
|
6月前
|
C语言
[字符串和内存函数]strcat字符串函数的详解和模拟
[字符串和内存函数]strcat字符串函数的详解和模拟
48 0
|
6月前
|
存储 C语言
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现2
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现
|
1月前
|
存储 C语言 数据格式
解析spritf和sscanf与模拟常用字符串函数strchr,strtok(二)
解析spritf和sscanf与模拟常用字符串函数strchr,strtok(二)
20 0
|
1月前
解析与模拟常用字符串函数strcpy,strcat,strcmp,strstr(一)
解析与模拟常用字符串函数strcpy,strcat,strcmp,strstr(一)
33 0
|
5月前
|
安全 编译器 C语言
C语言学习记录——字符串相关函数及部分模拟(strcmp、strncmp、strncat、strncpy、strstr、strtok、strerror)
C语言学习记录——字符串相关函数及部分模拟(strcmp、strncmp、strncat、strncpy、strstr、strtok、strerror)
49 1
|
6月前
|
C语言
C语言:字符函数和字符串函数(strlen strcat strcmp strncmp等函数和模拟实现)
C语言:字符函数和字符串函数(strlen strcat strcmp strncmp等函数和模拟实现)
|
6月前
|
C语言
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现2
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现
|
6月前
|
存储 C语言
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现1
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现
|
6月前
|
存储 C语言
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现1
【C语言】字符串函数strcpy&&strcat&&strcmp&&strstr的使⽤和模拟实现