strstr,strnstr函数详解

 strstr函数

strstr函数是C语言中的一个字符串函数,用于在一个字符串中查找另一个字符串的出现位置。

它的函数原型如下:

char *strstr(const char *haystack, const char *needle);

在这个函数中,haystack表示被搜索的字符串,needle表示要查找的子字符串。函数的返回值是一个指针,指向第一次出现needle的位置,如果没有找到,返回NULL。

例如,我们可以使用strstr函数来查找一个字符串中是否包含另一个字符串:

#include <stdio.h>
#include <string.h>int main() {char haystack[] = "Hello, world!";char needle[] = "world";char *result = strstr(haystack, needle);if (result != NULL) {printf("'%s' is found in '%s' at position %ld.\n", needle, haystack, result - haystack);} else {printf("'%s' is not found in '%s'.\n", needle, haystack);}return 0;
}

上述代码输出为:

'world' is found in 'Hello, world!' at position 7.

需要注意的是,strstr函数是区分大小写的,如果要进行大小写不敏感的查找,可以使用其他函数,例如strcasestr。

使用示例

查找子字符串成功后,用strncpy修改内存块内容。

#include <stdio.h>
#include <string.h> 
#include<assert.h>int main()
{char str[] = "This is a simple string hello world!";char* pch;pch = strstr(str, "string");if (pch != NULL){printf("%s\n",str);printf("%s\n",pch);strncpy(pch, "sifang",6);}printf("%s\n",str);printf("%s\n",pch);return 0;
}


输出结果:

 由输出的结果可知,pch的内容为str的子字符串,指向的地址是第一次相同的位置,也就是说pch指向的内存块是str所指向的内存块。当用strncpy修改pch所指向的内存块值时,其str所指向的对应内存块内容发生改变。

用memcpy替换strncpy,其输出的结果是相同的。

查找子字符成功,strncp的长度修改,引起结果异常。

#include <stdio.h>
#include <string.h> 
#include<assert.h>int main()
{char str[] = "This is a simple string hello world!";char* pch;pch = strstr(str, "string");if (pch != NULL){printf("%s\n",str);printf("%s\n",pch);strncpy(pch, "sifang",7);//只是将6修改为7}printf("%s\n",str);printf("%s\n",pch);return 0;
}

输出结果:

对比上面输出的结果可以看出,strncpy后,后面对字符串做了截断处理,这是因为strncpy时,只有sifang六个字符,而长度为7 ,因此将\0的结束字符也拷贝了,引起截断。这种情况和用strcpy的结果是一样的,因为strcpy拷贝自动带上结束符\0。

#include <stdio.h>
#include <string.h> 
#include<assert.h>int main()
{char str[] = "This is a simple string hello world!";char* pch;pch = strstr(str, "string");if (pch != NULL){printf("%s\n", str);printf("%s\n", pch);strcpy(pch, "sifang");}printf("%s\n", str);printf("%s\n", pch);return 0;
}

结果 

模拟实现

#include <stdio.h>  
#include <string.h>  
#include <assert.h>  char *my_strstr(const char *haystack, const char *needle) {  assert(haystack != NULL && needle != NULL); // 确保两个指针都不是NULL  if (*needle == '\0') {  // 如果needle是空字符串,则认为在haystack的开头就找到了  return (char *)haystack;  }  while (*haystack != '\0') {  const char *h = haystack;  const char *n = needle;  // 逐个字符比较haystack和needle  while (*h != '\0' && *n != '\0' && *h == *n) {  h++;  n++;  }  // 如果needle已经完全匹配,返回haystack的起始位置  if (*n == '\0') {  return (char *)haystack;  }  // 否则移动haystack到下一个字符  haystack++;  }  // 没有找到匹配项  return NULL;  
}  int main() {  const char *haystack = "Hello, world!";  const char *needle = "world";  char *result = my_strstr(haystack, needle);  if (result != NULL) {  printf("Found '%s' in '%s' at position: %ld\n", needle, haystack, result - haystack);  } else {  printf("'%s' not found in '%s'.\n", needle, haystack);  }  return 0;  
}

strnstr函数

strnstr函数是C语言标准库中的一个函数,用于在指定长度的字符串中查找第一次出现子串的位置。它的原型通常如下:

 char *strnstr(const char *s1, const char *s2, size_t n); 

其中:

  1. s1 是主字符串,即要搜索的字符串。
  2. s2 是子字符串,即要在 s1 中查找的字符串。
  3. n 是指定 s1 中参与搜索的最大字符数。

strnstr 函数从 s1 的开头开始,搜索 s2 在 s1 中首次出现的位置,但只搜索到 s1 的前 n 个字符。如果找到 s2,则返回指向 s1 中 s2 首次出现的位置的指针;如果没有找到,则返回 NULL。

这个函数在处理可能包含子串的字符串时非常有用,尤其是当你不确定整个字符串是否都包含在内,或者只关心字符串的一部分时。通过限制搜索的长度,你可以避免不必要的内存访问,并提高性能。

这里是一个简单的例子,演示了如何使用 strnstr 函数:

 #include <stdio.h>  #include <string.h>  int main() {  const char *s1 = "Hello, world!";  const char *s2 = "world";  size_t n = 12; // 只搜索 s1 的前 12 个字符  char *result = strnstr(s1, s2, n);  if (result != NULL) {  printf("Found '%s' in '%s' at position: %ld\n", s2, s1, result - s1);  } else {  printf("'%s' not found in '%s' (up to %zu characters).\n", s2, s1, n);  }  return 0;  } 

在这个例子中,strnstr 函数会在 s1 的前 12 个字符中搜索 s2("world")。因为 "world" 确实存在于这 12 个字符中,所以函数会返回指向 "world" 在 s1 中首次出现的位置的指针,并打印出该位置。如果 "world" 不在这 12 个字符中,或者 s1 本身少于 12 个字符,那么函数将返回 NULL。

模拟实现

strnstr函数的模拟实现可以有多种方式,下面我将提供两种基于不同策略的模拟实现,并加入assert语句来确保输入的有效性:

1. 朴素的循环实现

 #include <stdio.h>  #include <string.h>  #include <assert.h>  char *my_strnstr(const char *s1, const char *s2, size_t n) {  assert(s1 != NULL && s2 != NULL); // 确保s1和s2都不是NULL  if (n == 0) return NULL; // 如果n为0,则无法搜索,直接返回NULL  const char *p1 = s1;  const char *p2 = s2;  while (n--) {  if (*p2 == '\0') {  // 子串s2已结束,找到了匹配  return (char *)s1;  }  if (*p1 != *p2) {  // 当前字符不匹配,重置p2到s2的开头,p1移动到下一个字符  p2 = s2;  if (*p1 == '\0') {  // 主串s1已结束,没有找到匹配  return NULL;  }  p1++;  } else {  // 当前字符匹配,继续检查下一个字符  p1++;  p2++;  }  }  // 搜索完n个字符后仍未找到匹配  return NULL;  }  int main() {  const char *s1 = "Hello, world!";  const char *s2 = "world";  size_t n = strlen(s1); // 测试整个字符串  char *result = my_strnstr(s1, s2, n);  if (result != NULL) {  printf("Found '%s' in '%s' at position: %ld\n", s2, s1, result - s1);  } else {  printf("'%s' not found in '%s'.\n", s2, s1);  }  return 0;  } 

2. KMP(Knuth-Morris-Pratt)算法实现(简化版)

KMP算法是一种更高效的字符串匹配算法,但由于其实现相对复杂,这里仅提供一个简化的模拟版本。

 #include <stdio.h>  #include <string.h>  #include <assert.h>  // 简化的KMP算法实现(未完整实现KMP的所有优化)  char *my_strnstr_kmp(const char *s1, const char *s2, size_t n) {  assert(s1 != NULL && s2 != NULL);  if (n == 0) return NULL;  if (*s2 == '\0') return (char *)s1; // 如果s2为空字符串,则s1的任何位置都是匹配点  const char *p1 = s1;  const char *p2 = s2;  while (n--) {  if (*p1 == *p2) {  // 字符匹配,继续检查下一个字符  if (*p2 == '\0') {  // s2已结束,找到了匹配  return (char *)s1;  }  p1++;  p2++;  } else {  // 当前字符不匹配,重置p2到s2的开头,p1根据s2的某些性质移动(这里简化处理)  p2 = s2;  if (*p1 == '\0') {  // s1已结束,没有找到匹配  return NULL;  }  p1++;  }  }  // 搜索完n个字符后仍未找到匹配  return NULL;  }  int main() {  // ... 示例用法与上一个实现相同 ...  } 

注意:上面的KMP算法实现是一个简化的版本,它没有包含KMP算法中用于优化搜索过程的“部分匹配表”(Partial Match Table, PMT)或“失败函数”(Failure Function)。在实际应用中,完整的KMP算法会构建一个这样的表来加速搜索过程。
 

strstr和strnstr函数的区别

strstrstrnstr函数在C语言中用于字符串处理,但它们在功能和使用上有所不同。

  1. strstr函数:

    • 功能:用于在字符串str1中查找子字符串str2首次出现的位置。
    • 参数:接受两个字符串参数str1str2,其中str1是要被搜索的字符串,str2是要查找的子字符串。
    • 返回值:如果找到子字符串str2,则返回指向其在str1中首次出现的位置的指针;如果没有找到,则返回NULL
    • 特点:strstr函数会搜索整个str1字符串以查找str2,不考虑字符串的长度限制。
  2. strnstr函数:

    • 功能:与strstr类似,也是在字符串中查找子串,但允许指定要搜索的最大字符数。
    • 参数:除了接受两个字符串参数str1(主字符串)和str2(子字符串)外,还接受一个额外的参数n,表示在str1中参与搜索的最大字符数。
    • 返回值:与strstr相同,如果找到子字符串str2,则返回指向其在str1中首次出现的位置的指针;如果没有找到,则返回NULL
    • 特点:strnstr函数只会在str1的前n个字符中搜索str2,而不会搜索整个字符串。这在某些情况下可以提高效率,特别是当你知道子字符串不可能出现在主字符串的某个特定部分之后时。

总结来说,strstrstrnstr函数的主要区别在于是否允许指定搜索的最大字符数。如果你需要搜索整个字符串,可以使用strstr;如果你只想在字符串的某个特定部分中搜索,可以使用strnstr

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

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

相关文章

【多态】有关多继承和菱形继承的多态

博主首页&#xff1a; 有趣的中国人 专栏首页&#xff1a; C进阶 其它专栏&#xff1a; C初阶 | 初阶数据结构 | Linux 博主会持续更新 本篇文章主要讲解 多继承和菱形继承的多态 的相关内容 文章目录 1. 回顾多态底层2. 抽象类2.1 概念2.2 接口继承和实现继承 3. 虚表所在…

Linux——web建立wordpress

下载 [rootnfs-server ~]# yum install php wget https://wordpress.org/latest.tar.gz解压 /var/www/html [rootnfs-server html]# tar -xzvf latest.tar.gz [rootnfs-server html]# rm latest.tar.gz授权 [rootnfs-server html]# chown -R www:www /var/www/html添加文件备…

利用kimi等大模型进行运维参数解析和调优

在运维时&#xff0c;经常遇到很多参数&#xff0c;有些参数不知道意义&#xff0c;知道意义的也有些不知道合理参考值是多少。利用kimi等大模型来当老司机&#xff0c;轻松解决运维难题。 例如在运维hive参数时&#xff0c;有些不知道作用&#xff0c;提示次如下 你的角色是…

windows ubuntu sed,awk,grep篇:7.sed 多行模式及循环

目录 46.读取下一行数据并附加到模式空间(命令 N) 47.打印多行模式中的第一行(命令 P) 48. 删除多行模式中的第一行(命令 D) 49.循环和分支(命令 b 和 :label 标签) 50.使用命令 t 进行循环 Sed 默认每次只处理一行数据&#xff0c;除非使用 H,G 或者 N 等命令创建多行模式&…

python学习笔记B-11:序列结构之列表--二维列表的遍历和生成式

二维列表的遍历方式&#xff0c;使用双层for循环&#xff0c;遍历索引号。 二维列表的生成式&#xff0c;也是使用类似双层循环的形式生成。 print("##初始化二维列表&#xff0c;每个元素就是1个列表") lst [["东方延续","太空军自然选择号舰长&qu…

释放Stable Diffusion 无限可能

最近在整理大语言模型的系列内容&#xff0c;Stable Diffusion 是我下一篇博客的主题。关注 Stable Diffusion&#xff0c;是因为它是目前最受欢迎和影响力最大的多模态生成模型之一。Stable Diffusion 于 2022 年 8 月发布&#xff0c;主要用于根据文本的描述产生详细图像&…

基于SpringBoot+Vue笔记记录分享网站设计与实现

项目介绍&#xff1a; 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代…

C语言 | Leetcode C语言题解之第50题Pow(x,n)

题目&#xff1a; 题解&#xff1a; double myPow(double x, int n){if(n 0 || x 1){return 1;}if(n < 0){return 1/(x*myPow(x,-(n1)));}if(n % 2 0){return myPow(x*x,n/2);}else{return x*myPow(x*x,(n - 1)/2);} }

【Jenkins】持续集成与交付 (三):有关报错解决(Jenkins (2.387.3) or higher required)

🟣【Jenkins】持续集成与交付 (三):有关报错解决Jenkins (2.387.3) or higher required 一、Jenkins主页报错二、安装Jenkins插件报错三、解决过程(解压替换jenkins.war)四、重新访问登录💖The Begin💖点点关注,收藏不迷路💖 一、Jenkins主页报错 New version …

吴恩达2022机器学习专项课程(一)7.2 逻辑回归的简化成本函数

问题预览/关键词 本节课内容逻辑回归的损失函数简化之后的形式是&#xff1f;为什么可以简化&#xff1f;成本函数的通用形式是&#xff1f;逻辑回归成本函数的最终形式是&#xff1f;逻辑回归为什么用对数损失函数计算成本函数&#xff1f;为什么不直接给出逻辑回归损失函数的…

[详解]Spring AOP

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring学习之路&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 什么是AOP? Spring AOP 快速入门 Spring AOP核心概念 切点(Point…

selenium 4.x入门篇(环境搭建、八大元素定位)

背景 Web自动化测现状 1. 属于 E2E 测试 2. 过去通过点点点 3. 好的测试&#xff0c;还需要记录、调试网页的细节 一、selenium4.x环境搭建 一键搭建 pip3 install webdriver-helper 安装后自动的完成&#xff1a; 1. 查看浏览器的版本号 2. 查询操作系统的类型…

【智能优化算法】蚱蜢优化算法(Grasshopper Optimization Algorithm,GOA)

蚱蜢优化算法(Grasshopper Optimization Algorithm&#xff0c;GOA)是期刊“IEEE Access”&#xff08;IF 3.9&#xff09;的2021年智能优化算法 01.引言 蚱蜢优化算法(Grasshopper optimization algorithm, GOA)&#xff0c;并将其应用于结构优化中的挑战性问题。该算法在数学…

Microsoft Edge浏览器:高效、简洁、个性化的网页浏览体验

Microsoft Edge是微软公司推出的一款网络浏览器&#xff0c;它是基于Chromium开源项目开发的&#xff0c;因此与Google Chrome有很多相似之处。以下是一些使用Microsoft Edge的心得体会&#xff1a; 1. 界面简洁&#xff1a;Microsoft Edge的界面设计非常简洁&#xff0c;用户…

华为od入职第13天!

今天早上就分配活了&#xff0c;写一个模块的ut&#xff0c;但是今天一句代码没写成&#xff0c;一直在看代码逻辑。下午就是新员工的一个会&#xff0c;部门20来个人做一下自我介绍啥的。晚上我导师给我们几个新员工讲项目框架和一些代码逻辑啥的&#xff0c;讲了一个多小时&a…

区块链技术与应用学习笔记(5-7节)——北大肖臻课程

​ 目录 ​BTC实现 基于交易的账本模式&#xff1a; UTXO集合&#xff1a; 交易费用&#xff1a; BTC网络 1.应用层&#xff1a; 2.网络层&#xff1a; 3传播层&#xff1a; 什么是鲁棒&#xff1f; BTC挖矿&#xff1a; 出块奖励&#xff1a; 挖矿难度调整&#…

Python | Leetcode Python题解之第51题N皇后

题目&#xff1a; 题解&#xff1a; class Solution:def solveNQueens(self, n: int) -> List[List[str]]:def generateBoard():board list()for i in range(n):row[queens[i]] "Q"board.append("".join(row))row[queens[i]] "."return b…

【C语言刷题系列】对数字添加逗号

目录 一、问题描述 二、解题思路 三、源代码 拓展&#xff1a; 个人主页&#xff1a; 倔强的石头的博客 系列专栏 &#xff1a;C语言指南 C语言刷题系列 一、问题描述 二、解题思路 题目的要求&#xff0c;即对于一个较大的整数&#xff0c;每三位数字之间添加…

CSS + HTML

目录 一.CSS&#xff08;层叠样式表&#xff09; 二. CSS 引入方式 三.选择器 3.1 标签选择器 3.2 类选择器 3.3 id选择器 3.4 通配符选择器 3.5 画盒子 四.文字控制属性 4.1字体大小 4.2字体粗细 4.3 字体倾斜 4.4行高 4.5行高--垂直居中 4.6 字体族 4.7 字体复…

使用mmdetection来训练自己的数据集(visdrone)(四)结果分析

测试 python tools/test.py <your-config-file> <your-model-weights-file> --out <save-pickle-path>关于test.py 的命令行 parser.add_argument(--out,typestr,helpdump predictions to a pickle file for offline evaluation)计算量、参数量计算脚本 pyth…