C语言字符串查找核心函数:strstr与strtok用法及模拟实现

小满
小满
发布时间:2026-10-13 | 5人浏览过
原创

掌握C语言中用于字符串处理的strstr与strtok函数,能够高效完成文本解析任务。本文不仅涵盖两函数的标准用法,更通过代码演示其参数传递规则,并深度解析strstr的内部匹配机制与模拟实现。

strstr 字符串定位函数

strstr 是 C 语言标准库 <string.h> 中用于查找子字符串的核心函数。它的基本功能是在一个长字符串中定位指定子串的首次出现位置。

函数原型如下:

char *strstr( const char *string, const char *strCharSet );

返回值说明:

  • 如果 strCharSet(目标子串)存在于 string(源字符串)中,函数返回指向该子串在源字符串中第一次出现位置的指针。
  • 如果不存在,返回 NULL(空指针)。
  • 特殊情况下,如果 strCharSet 指向空字符串(长度为 0),函数直接返回源字符串 string 本身。

由于返回值是指针类型,我们在接收结果时通常也需要定义一个指针变量。下面通过代码示例来观察其行为。

第1步:正常查找子串

当目标子串确实存在时,我们可以利用返回值进行后续操作,例如打印从该位置开始的字符串内容。

#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[] = "abbbcdbbcef";
	char arr2[] = "bbc";
	// ret 保存找到的子串起始位置的指针
	char* ret = strstr(arr1, arr2);
	
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		// 打印从匹配位置开始到结束的部分
		printf("%s\n", ret);
	}
	return 0;
}

第2步:处理未找到目标的情况

调整输入数据,使目标子串在原字符串中不存在。此时函数应返回空指针,程序逻辑需对此进行处理。

// ... 省略部分代码 ...
	char arr2[] = "bbcq"; // 假设要查找包含 q 的子串
	char* ret = strstr(arr1, arr2);
	// ...

模拟实现 strstr

理解库函数的行为有助于更高效地使用它,而模拟实现则能揭示其底层逻辑。strstr 的实现涉及指针的移动与回退机制,这也是面试和算法学习中常见的考点。

核心逻辑分析

在逐个字符比对的过程中,主要面临两种情况:

情况一:字符连续匹配成功

这是理想路径。当主串当前字符与子串首字符相等时,两者同时向后移动。若一直匹配直到子串结束符 '\0',则证明匹配成功,返回当前位置。

情况二:中途匹配失败

这是容易出错的点。假设我们同时在比较主串和子串的字符,当发现某一位不相等时:
- 子串的指针需要重置到子串的首地址,重新开始尝试。
- 主串的指针不能简单跳过,而是要回到本次尝试开始位置的下一个字符,重新发起匹配。

为了保证不影响原始的主串遍历入口,我们需要引入临时变量来维护当前的比对位置,并保留一个记录“本轮匹配起点”的哨兵指针。

模拟实现代码

以下是完整的 my_strstr 实现逻辑,包含断言检查和空串保护:

#include <string.h>
#include <assert.h>

char* my_strstr(const char* str1, const char* str2)
{
	// 确保传入指针有效
	assert(str1 && str2);
	
	// 如果子串为空,直接返回主串首地址
	if (*str2 == '\0')
	{
		return (char*)str1;
	}
	
	const char* s1 = NULL;
	const char* s2 = NULL;
	// cp 用于记录每一轮比对在主串中的起始位置
	const char* cp = str1;
	
	while (*cp) 
	{
		// 初始化本轮比对:s1 指向当前起始位,s2 指向子串头
		s1 = cp;
		s2 = str2;
		
		// 当主串没结束、子串没结束、且对应字符相等时,持续向后比对
		while (*s1 !='\0' && *s2!='\0' && *s1 == *s2)
		{
			s1++;
			s2++; 
		}
		
		// 关键点:如果 s2 到达了 '\0',说明子串全部匹配成功
		if (*s2 == '\0')
		{
			return (char*)cp; // 返回成功的起始位置
		}
		
		// 当前位匹配失败,主串起始位置向后移一位,准备下一轮
		cp++;
	}
	
	return NULL; // 遍历完仍未找到
}

strtok 字符串分割函数

在处理日志、配置文件或 CSV 数据时,经常需要将长字符串按特定符号切割成若干片段。此时 strtok 是最常用的工具。

工作原理与特性

函数原型:

char *strtok( char *strToken, const char *strDelimit );

它的工作机制非常独特,甚至可以说具有“副作用”:

  1. 破坏性修改:strtok 会在每次找到一个标记后,用 '\0' 替换分隔符,从而切断字符串。因此,被操作的字符串必须是可修改的(如数组拷贝),绝不能操作只读字符串常量。
  2. 状态保持:函数内部会保存当前正在处理的字符串的剩余部分位置。首次调用需要传入待分割的字符串;随后的调用只需传入 NULL,函数即可基于上次的状态继续寻找下一个标记。
  3. 多分隔符支持:strDelimit 是一个字符集合,字符串中包含的任何属于该集合的字符都会被视为分隔符。

实战:分割邮箱地址

假设要将邮箱 superverybest@outlooks.net 按照 @ 和 . 进行拆分。

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[] = "superverybest@outlooks.net";
	const char* sep = "@."; // 定义分隔符集合
	
	char buf[50] = { 0 };
	// 注意:strtok 会修改原字符串,所以先拷贝一份
	strcpy(buf, arr); 
	
	char* ret = NULL;
	
	// 循环获取每一个分片
	// 第一次传入 buf,之后传入 NULL
	for (ret = strtok(buf, sep); ret != NULL; ret=strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
	
	return 0;
}

总结

strstr 侧重于内容的精准检索,理解其指针回溯机制能有效避免手动实现时的逻辑漏洞;strtok 侧重于文本的结构化解析,使用时务必牢记其“就地修改”的特性,提前备份字符串即可安全使用。以上就是C语言进阶之字符串查找库函数详解的详细内容,更多关于C语言字符串操作技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表