【C语言】字符串函数介绍三(strstr、strtok、streeror)

news2025/1/12 1:36:03

前言

之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp这些函数

第一篇文章strlen、strcpy、stract

第二篇文章strcmp、strncpy、strncat、strncmp

今天我们就来学习:

话不多说,我们直接开始

strstr

返回值

如果s2是s1的子串,就返回子串的首元素地址,
如果没找到,就返回空指针

补充说明

当s1中存在多个s2时,其返回的地址,是s2在s1中第一次出现的地址

一般情况

int main()
{
	char* p1 = "abcdefabcdef";
	char* p2 = "def";
	char * ret = strstr(p1, p2);
	if (ret == NULL)
	{
		printf("0\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

模拟实现

基本思路

两种情况:
*s1 == *s2
*s1 != *s2

*s1 == *s2

s1向后移动,s2也向后移动,看是否继续相等

while (*s1 == *s2)
{
	s1++;
	s2++;
}

*s1 != *s2

s1不动,s2向后移动一位,看二者是否相等

while (*s1 == *s2)
{
	s1++;
	s2++;
}
s1++;

问题1

当s2是’\0‘时,说明要查找的字符串已经结束了,这时就结束查找

问题2

当s1是’\0‘时,说明被查找的字符串已经结束了,这时就结束查找

问题3

当我们真的找到这个子串的时候,想要返回首元素地址,却发现s2指向的是字串的最后一个元素。

问题4

当字符串1为“abbbc”,字符串2为“bbc”时,
是得不到正确结果的,因为s2指向的已经是第二个b了,s1指向的也是第二个b

解决方案

想解决问题三和四,就单独创建两个变量p1、p2来存储s1和s2就行了

并且,当s1和s2指向的元素相等时,要创建一个变量cur来记录这个位置,方便s1和s2回到这个位置继续查找。

最终代码

char* my_strstr(const char* s1, const char* s2)
{
	assert(s1 && s2);
	if (*s2 == 0)//当s2是空字符串时,传进来的s2是‘\0’
	{
		return (char*)s1;//此时直接返回s1即可
	}
	
	char* p1 = s1;
	char* p2 = s2;
	char* cur = s1;

	while (*cur)
	{
		p1 = cur;
		p2 = s2;
		while ((*p1 == *p2) && (*p1 != '\0') && (*p2 != '\0'))
		{
			p1++;
			p2++;
		}
		if (*p2 == '\0')
		{
			return cur;
		}
		cur++;
	}
	return NULL;

}

int main()
{
	char* p1 = "abcdef";
	char* p2 = "def";
	char* ret = strstr(p1, p2);
	if (ret == NULL)
	{
		printf("0\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

写的还是比较清晰的,有疑问可以在文章下面留言~

strstr函数在编译器中的实现

我没在库里找到这个文件,所以在网上复制了一份源码

#include <stdio.h>char * __cdecl strstr(const char *str1, const char *str2)
{
    char *cp = (char *)str1;
    char *s1, *s2;if (!*str2)
        return((char *)str1);while (*cp)
    {
        s1 = cp;
        s2 = (char *)str2;while (*s2 && !(*s1 - *s2))
            s1++, s2++;if (!*s2)
            return(cp);
​
        cp++;
    }return(NULL);
}int main(int argc, char *argv[], char *envp[])
{
    char str[] = "asfasfas";
    char *p = "asas";
    char ret = '0';
    ret = strstr(str, p);
    if (ret != NULL)
    {
        printf("%c", ret);
    }
    else
    {
        printf("NULL");
    }
    return 0;
}

补充说明,在源代码中,我们可以看到参数都用const保护起来了,所以在返回值那里需要进行强制类型转换(char*)
//虽然不转换代码也能运行,但还是严谨一点好

拓展

KMP算法和上面的实现过程结果是一样的,但更高级,感兴趣的可以去了解一下

strtok(会用即可)

介绍

  1. sep参数是个字符串,定义了用作分隔符的字符合集
    2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
    记。
    3.strtok函数找到str中的下一个标记,并将其用 \0结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
    4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
    5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。
    6.如果字符串中不存在更多的标记,则返回NULL 指针。

详细解释

下面我们看一段代码,来实际应用一下

int main()
{
	char arr[] = "hello@world.nicetomeetyou";
	char* p = "@.";

	char buff[10000] = { 0 };
	strcpy(buff, arr);

	char* ret = strtok(arr, p);
	printf("%s\n", ret);

	return 0;
}

1.p就是sep,里面的字符就是分隔符

2.arr就是str

3.strtok函数会从str开始,逐个向后查找,当找到sep中的分隔符时,strtok就将它改成’\0’,并返回分割出的这个字符串的首元素地址。
下一次查找就从\0后面开始寻找(等于是创建了一个静态变量存储’\0’后面的元素的地址)

4.当第二个参数不为NULL时,从sep中的的第一个分隔符开始查找

5.当第二个参数为NULL时,那就进入sep中的下一个分隔符开始查找
意思就是:查找第二个分隔符

6.当字符串str中遇到\0时,就结束查找,并返回NULL

注意:

strtok函数会破坏被查找的字符串,所以我们需要将原字符串拷贝一份,再进行查找

实际应用

像上文那样使用的话,有几个字符串,就得写几次
但实际上,我们并不会像上面那段代码那样使用strtok函数,

在上文“详细解释”中,第六点提到:当str中遇到\0时,就返回NULL

所以我们可以先创建一个变量ret定义为NULL
使用for循环来打印出分割的多个字符串

	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}

(很神奇的一种使用方式)

strerror

介绍

char * strerror ( int errnum )

返回错误码,所对应的错误信息

使用方法

传入一个整数,输出一个地址

int main()
{
	char* str = strerror(0);
	printf("%s\n", str);

	return 0;
}

运行结果:
在这里插入图片描述

此处传入的整数,被称为错误码

每个错误码,都对应一个错误信息
如:
0:No error
1:Operation not permitted

实际使用

但在实际应用中,错误码不会由我们传入,而是输入errno,
errno是一个全局的错误码变量
当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值给errno
需要包含头文件<errno.h>

举例

C语言中我们使用fopen函数来打开一个文件

int main()
{
	FILE* pf = fopen("test.txt", "r");
	//要打开文件的名称是test.txt,打开方式是"r",读取这个文件
	//这个函数会返回一个FILE*的指针
	if (pf == NULL)
	//当返回为空指针,说明读取失败
	//但读取失败有很多原因,可能是文件不存在,可能是访问权限不够等等
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("open file success\n");
	}

	return 0;
}

这里我们就可以通过strerror函数,来找到确切的原因
运行结果

没有这样的文件或目录

在这里插入图片描述

errno

想知道更多可以直接转到定义查看不同的整数对应的错误信息

在这里插入图片描述

结语

字符串函数就介绍到这里了,下一篇文章我们会学习字符分类函数
我们明天见~

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

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

相关文章

护航顶级赛事 | 以赛事空间信息服务助力大运会有序运行

8月8日&#xff0c;第31届世界大学生夏季运动会在成都圆满闭幕。此前&#xff0c;赛事组委会与相关部门着力建设“综合运行管理中心系统(后简称“MOC”系统)”&#xff0c;利用信息化手段&#xff0c;实现了对赛前、赛中、赛后各个阶段、各个对象、各个服务的信息化监管&#x…

用讯飞星火认知大模型构建一个带界面的聊天机器人

在本篇博客中&#xff0c;我们将使用 最新的星火认知大模型和 Tkinter 构建一个简单的聊天机器人界面。通过这个界面&#xff0c;用户可以与聊天机器人进行交互&#xff0c;并查看机器人的回答。 C:\pythoncode\blog\static_16919367030710594_SparkApi_Python\testui.py 准备…

Kubernetes二进制部署方案

目录 一、环境准备 2.1、主机配置 2.2、安装 Docker 2.3、生成通信加密证书 2.3.1、生成 CA 证书&#xff08;所有主机操作&#xff09; 2.3.2、生成 Server 证书&#xff08;所有主机&#xff09; 2.3.3、生成 admin 证书(所有主机) 2.3.4、生成 proxy 证书 三、部署 …

Java多态详解(1)

多态 多态的概念 所谓多态&#xff0c;通俗地讲&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 比如&#xff1a; 这一时间爆火的“现代纪录片”中&#xff0c;麦克阿瑟总是对各种“名人”有不同的评价&…

Linux常用命令——dircolors命令

在线Linux命令查询工具 dircolors 置ls命令在显示目录或文件时所用的色彩 补充说明 dircolors命令设置ls命令在显示目录或文件时所用的色彩。dircolors可根据[色彩配置文件]来设置LS_COLORS环境变量或是显示设置LS_COLORS环境变量的命令。 语法 dircolors(选项)(参数)选项…

如何区分闰年与平年

首先要明白 地球绕太阳运行周期为365天5小时48分46秒&#xff08;合365.24219天&#xff09;&#xff0c;即一回归年&#xff08;tropical year&#xff09;。公历的平年只有365日&#xff0c;比回归年短约0.2422 日&#xff0c;每四年累积约一天&#xff0c;把这一天加于2月末…

指令:指令执行过程、指令寻址、指令组成、数据寻址、补充(扩展操作码指令格式)

计算机的工作过程是执行程序的过程&#xff0c;程序是一系列按一定顺序执行的指令。 指令是指挥机器执行某种操作的命令&#xff0c;是计算机运行的最小功能单元&#xff08;一组二进制代码&#xff09;。 指令系统&#xff1a;计算机中所有指令的集合&#xff0c;也称指令集…

idea安装插件JRebel

一、安装插件 二、下载代理服务并启动 首先下载服务&#xff0c;网址 Releases ilanyu/ReverseProxy (kgithub.com) 下载后直接双击运行&#xff0c;杀毒软件可以会报警告&#xff0c;直接忽略就行 启动好&#xff0c;等着就行&#xff0c;接下来会用到。 三、在线获取GUID …

通讯协议044——全网独有的OPC HDA知识一之聚合(十二)持续坏值时间

本文简单介绍OPC HDA规范的基本概念&#xff0c;更多通信资源请登录网信智汇(wangxinzhihui.com)。 本节旨在详细说明HDA聚合的要求和性能。其目的是使HDA聚合标准化&#xff0c;以便HDA客户端能够可靠地预测聚合计算的结果并理解其含义。如果用户需要聚合中的自定义功能&…

Python绘图系统6:自定义坐标列表控件

文章目录 自定义坐标列表控件显示和隐藏加载按钮坐标设置控件的显示和隐藏源代码 Python绘图系统&#xff1a; 基础&#xff1a;将matplotlib嵌入到tkinter &#x1f4c8;简单的绘图系统 &#x1f4c8;数据导入&#x1f4c8;三维绘图系统自定义控件&#xff1a;坐标设置控件&a…

Threejs学习04——球缓冲几何体环境光以及直线光源

实现随机多个三角形随机位置随机颜色展示效果 这是一个非常简单基础的threejs的学习应用&#xff01;本节主要学习的是球面缓冲几何体在环境光合直线光源下的效果&#xff0c;可以学习到环境光和直线光源的生成效果等功能&#xff01;主要使用的是球缓冲几何体对象SphereGeome…

综合能源系统(8)——综合能源系统支撑技术

1、大数据技术 1.1、大数据技术概述 大数据是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 维克托迈尔舍恩伯格和肯尼斯克耶编写…

【面试八股文】每日一题:谈谈你对IO的理解

谈谈你对IO的理解 每日一题-Java核心-谈谈你对对IO的理解【面试八股文】 1.Java基础知识 Java IO&#xff08;Input/Output&#xff09;是Java编程语言中用于处理输入和输出的一组类和接口。它提供了一种在Java程序中读取和写入数据的方法。 Java IO包括两个主要的部分&#x…

从零开始学习 Java:简单易懂的入门指南之Objects、BigInteger、BigDecimal(十四)

常用API&#xff0c;Objects、BigInteger、BigDecimal 5 Objects类5.1 概述5.2 常见方法 6 BigInteger类6.1 引入6.2 概述6.3 常见方法6.4 底层存储方式&#xff1a; 7 BigDecimal类7.1 引入7.2 概述7.3 常见方法7.4 底层存储方式&#xff1a; 5 Objects类 5.1 概述 tips&…

optee中如何开启或关闭所有中断的

我们知道在Linux Kernel中开启或关闭中断的函数是:local_irq_enable()和local_irq_disable(), 那么在optee os中是怎样做到的呢? optee中通过使用thread_mask_exceptions()和thread_unmask_exceptions()来开启或关闭中断。 thread_mask_exceptions()和thread_unmask_excepti…

C语言:选择+编程(每日一练)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;尼科彻斯定理 示例1 题二&#xff1a;等差数列 示例2 本人实力有限可能对一些地方解释和理解的不够清晰&…

【C++深入浅出】初识C++中篇(引用、内联函数)

目录 一. 前言 二. 引用 2.1 引用的概念 2.2 引用的使用 2.3 引用的特性 2.4 常引用 2.5 引用的使用场景 2.6 传值、传引用效率比较 2.7 引用和指针的区别 三. 内联函数 3.1 内联函数的概念 3.2 内联函数的特性 一. 前言 上期说道&#xff0c;C是在C的基础之上&…

Linux Kernel的local_irq_enable()和local_irq_disable()函数

代码如下图所示&#xff0c;最终操作的是msr daifset, #3 和 msr daifclr, #3 寄存器。 (include/linux/irqflags.h) #define local_irq_enable() do { raw_local_irq_enable(); } while (0) #define local_irq_disable() do { raw_local_irq_disable(); } while (0)#define ra…

历数浙大MPA提前批面试的三大变化

从2019年招生开始&#xff0c;浙大mpa项目的招生趋势一直处于稳增状态&#xff0c;特别是提前批面试政策的出现&#xff0c;更加为项目的整体招录添上神奇的一笔。为什么要举行提面&#xff1f;一方面报考的人数比较多&#xff0c;有了选拔的余地和基础&#xff1b;另一方面也能…

Python学习笔记_进阶篇(一)_浅析tornado web框架

tornado简介 1、tornado概述 Tornado就是我们在 FriendFeed 的 Web 服务器及其常用工具的开源版本。Tornado 和现在的主流 Web 服务器框架&#xff08;包括大多数 Python 的框架&#xff09;有着明显的区别&#xff1a;它是非阻塞式服务器&#xff0c;而且速度相当快。得利于…