当前位置: 首页 > news >正文

C语言函数: 字符串函数及模拟实现strtok()、strstr()、strerror()

C语言函数: 字符串函数及模拟实现strtok()、strstr()、strerror()

strstr()函数:

        作用:字符串查找。在一串字符串中,查找另一串字符串是否存在。

形参:

4b2e6b20082d41528eadfab74266debc.png

       str2在str1中寻找。返回值是char*的指针

        原理:如果在str1中找到了str2,则返回在str1中存在的str2的字符串的第一个字符的地址。如果在str1中每找到str2,则返回NULL(空指针)。

举例:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>int main()
{char arr1[] = "abcdefgh";char arr2[] = "bcde";char arr3[] = "bcdeh";char* a1 = strstr(arr1, arr2);char* a2 = strstr(arr1, arr3);return 0;
}

        a1是在arr1中寻找arr2,在arr1[1]~arr1[4]上找到了与arr2一样的字符串,则返回arr1中字符'b'的地址。

        a2是在arr1中寻找arr3,在arr1中并未找到与arr1一样的字符串,则返回NULL。

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>int main()
{char arr1[] = "abcdefgh";char arr2[] = "bcde";char arr3[] = "bcdeh";char* a1 = strstr(arr1, arr2);char* a2 = strstr(arr1, arr3);if (a1 != NULL){printf("arr2找到了");//结果:arr2找到了}if (a2 == NULL){printf("arr3没找到");//结果:arr3没找到}return 0;
}

strstr()函数的模拟实现:

char* my_strstr(const char* str1, const char* str2)//因为两个地址值不会改变,所以加const
{assert(str1 && str2);//防止两个参数为NULLchar* pt1 = NULL;char* pt2 = NULL;char* nc = str1;//用于在字符串中找到与str2首元素一样字符。while (*nc)//当str1中找完了,都没有找到和str2中首元素一样的字符时停止循环。{pt1 = nc;//用于定位到每次找到和str2中首元素一样的字符的地址。pt2 = str2;//用于指向str2的首元素地址。while (*pt1 && *pt2 && ( * pt1 == *pt2))//找到和str2中首元素一样的字符{pt1++;pt2++;}if (*pt2 == '\0')//当上面的循环走完,ptr2的指向\0时,说明在str1中找到了和str2一样的字符串{return nc;//返回当时的字符串。}nc++;//当这个str1中的元素和str2不匹配,就要看下一个字符是否匹配。}return NULL;
}

        

int main()
{char arr1[] = "abbcdef";char arr2[] = "bcd";char* a1 = my_strstr(arr1, arr2);if (a1 != NULL){printf("arr2找到了\n");//结果:arr2找到了}else{printf("arr2没找到\n");}return 0;
}

        

补充:还有一种算法:KMP算法。也是一个字符串查找的算法。


strtok()函数:

        作用:对字符串进行切分(分割)

        #include <string.h>

参数:

a8252c78062a410c91484cd68d05255b.png

        str是将被分割的字符串

        sep是需要传入的是字符串,sep内包含了需要作为分割符的字符的集合

        71ff5a9b43c14eddb52b3d06b567d768.png

        如果要将str中分为三个部分:www、qq、com

        那么就需要在@和.处进行分割。因此,@和.就是分割符,将分隔符放入sep字符串中,此时就是 :分割符的字符的集合

       

原理:

       这里有个字符串str :"www@qq.com\0"

        strtok()会将按照sep所指示的,在str中寻找sep内存在的字符。

        找到@后,会将@改成\0。

        strtok()返回@之前的字符串的首元素地址,即:str中第一个'w'的地址。

        并且strtok会记录此时\0的位置。

        strtok有两种机制:

        1.如果strtok不为NULL,那么会保存@的位置(@会被改成\0)     

        2.如果strtok为 NULL,那么会从上次strtok所保存@的位置,继续往下找seq中的字符,如果找到,接着分割。最后再保存被改成\0的位置。

        最后:如果strtok找到了没被改的\0,也就是字符串末尾的\0时,返回NULL。

        

        那么有疑问了,strtok是怎么保存@的位置呢?

        其实,想要保存某个数据,实际上就是创建一个全局变量。只要创建了全局变量,程序运行到哪里,无论在哪个函数中,都可以被使用。

        因此,strtok就是利用全局变量的能力,从而保存了@的位置。那么strtok是怎么保存的呢?难道直接在代码中写上一个全局变量吗?显然不是。

        strtok其实是使用static修饰了存放@位置的变量,因为static基本含义就是让一个变量成为全局变量。

        static函数名除了对该函数声明的文件可见外,其他文件都无法访问。也就是只能被本文件中的函数调用,而不能被同一程序中的其他文件的函数调用。

        static可以限定变量或函数为静态存储。静态函数会被自动分配在一个一直使用的存储区,直到程序结束才从内存消失,static限定的变量或函数不会和同一程序中其他文件同名的相冲突。如果用static限定内部变量,则该变量从程序一开始就用有内存,不会随其所在函数的调用和退出而分配和消失。

        

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <assert.h>void cc()
{static int opp = 0;opp++;printf("%d", opp);
}int main()
{cc();//结果:1int opp = 3;cc();//结果:2return 0;
}

使用建议:

        因为strtok的会对str字符串本身进行修改,如果不想对strtok进行修改时,可以用strcpy进行拷贝,然后对拷贝的字符串使用strtok

        

char arr[] = "www@qq.com";char* p = "@.";char tmp[20] = { 0 };strcpy(tmp, arr);//拷贝

实验:

        

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <assert.h>
#include <string.h>int main()
{char arr[] = "www@qq.com";char* p = "@.";char tmp[20] = { 0 };strcpy(tmp, arr);char* ret = NULL;ret = strtok(tmp, p);printf("%s\n", ret);//wwwret = strtok(NULL,p);printf("%s\n", ret);//qqret = strtok(NULL, p);printf("%s\n", ret);//comret = strtok(NULL, p);printf("%s\n", ret);//(null)return 0;
}

        创建了一个ret用于存放,每次strtok返回的字符串首元素地址。

        第一次调用 strtok(tmp, p)拿到了(返回)'w'的地址,保存了@(\0)的位置。

        第二次调用strtok(NULL,p)拿到了(返回)'q'的地址,保存了.(\0)的位置。

        第三次调用strtok(NULL,p)拿到了(返回)'c'的地址,\0的位置。

        第四次调用strtok(NULL,p)拿到了(返回)NULL,这是因为\0后面找不到p内包含的字符了。

        结果打印三个部分:www、qq、com

代码强化:

        这一个一个地调用strtok显然是不合理地。

        并且我们发现除了第一次调用strtok,传入地第一个参数是一个活指针之外,后面的几次调用使用的都是NULL,因此我们可以创建一个循环,从而分割它们。

        

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <assert.h>
#include <string.h>int main()
{char arr[] = "www@qq.com";char* p = "@.";char tmp[20] = { 0 };strcpy(tmp, arr);char* ret = NULL;for ( ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p)){printf("%s\n", ret);}return 0;
}

        for(初始化值;判断条件;对值改变)

        初始化值,执行了strtok第一次调用。

        判断条件,如果为strtok返回了NULL,说明没有分隔符了,for循环就停止。

        对值改变,做到了除第一次以外,后n次地对strtok地调用。

        

模拟实现:

       C语言源码剖析与实现——strtok()系列函数实现_strtok源码_C+G的博客-CSDN博客


strerror

        作用:翻译错误码。在使用库函数的时候,如果失败了都会出现错误码,而这串错误码你完全不懂是什么意思,比如:5,这个错误码的意思是什么呢?肯定不知道吧。

        错误码的作用是告诉你,你的代码执行过程中出现的错误。比如内存空间不足等等...

参数:

        头文件:#include <string.h>

d954914288674d1ebd423beeb356dcfd.png

        strerror返回的是一个地址,这个地址指向了一个字符串。这个字符串就是strerror从错误码所翻译出来的一句话。

        

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>int main()
{printf("%s\n", strerror(0));printf("%s\n", strerror(1));printf("%s\n", strerror(2));return 0;
}

 

        除此之外,还有许多C语言内部的错误码。

errno:

        errno是C语言定义的一个全局变量,它的作用是存放代码执行过程中出现的错误码。

        它不需要人为的定义,当用到它的时候只需要引头文件:#include <errno.h>

        

举例:

        

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>int main()
{//fopen:打开文件FILE* pf = fopen("test.txt", "r");//test.txt不存在if(pf ==NULL)//fopen找不到test.txt会返回空指针printf("%s\n", strerror(errno));//返回错误信息return 0;
}

模拟实现:

        单纯的翻译代码,因此不做实现。

 

相关文章:

C语言函数: 字符串函数及模拟实现strtok()、strstr()、strerror()

C语言函数&#xff1a; 字符串函数及模拟实现strtok()、strstr()、strerror() strstr()函数: 作用&#xff1a;字符串查找。在一串字符串中&#xff0c;查找另一串字符串是否存在。 形参: str2在str1中寻找。返回值是char*的指针 原理&#xff1a;如果在str1中找到了str2&…...

【学习笔记】人工智能哲学研究:《心智、语言和机器》

关于人工智能哲学&#xff0c;我曾在这篇文章里 【脑洞大开】从哲学角度看人工智能&#xff1a;介绍徐英瑾的《心智、语言和机器》 做过介绍。图片来源&#xff1a;http://product.dangdang.com/29419969.html在我完成了一些人工智能相关的工作以后&#xff0c;我再来分享《心智…...

设计模式之门面模式(外观模式)

目录 1.模式定义 2.应用场景 2.1 电源总开关例子 2.2 股民炒股场景 ​编辑 3. 实例如下 4. 门面模式的优缺点 传送门&#xff1a; 项目中用到的责任链模式 给对象讲工厂模式&#xff0c;必须易懂易会 策略模式&#xff0c;工作中你用上了吗&#xff1f; 1.模式定…...

MySQL - 多表查询

目录1. 多表查询示例2. 多表查询分类2.1 等/非等值连接2.1.1 等值连接2.1.2非等值连接2.2 自然/非自然连接2.3 内/外连接2.3.1 内连接2.3.2 外连接3.UNION的使用3.1 合并查询结果3.1.1 UNION操作符3.1.2 UNION ALL操作符4. 7种JOIN操作5. join 多张表多表查询&#xff0c;也称为…...

自定义报表是什么?

自定义报表是指根据用户的需求和要求&#xff0c;自行设计和生成的报表。自定义报表可以根据用户的具体需求&#xff0c;选择需要的数据和指标&#xff0c;进行灵活的排列和组合&#xff0c;生成符合用户要求的报表。自定义报表可以帮助用户更好地了解业务情况&#xff0c;发现…...

windows安装docker-小白用【避坑】【伸手党福利】

目录实操开启 Hyper-V 和容器特性下载docker安装dockercmd中&#xff0c;使用命令测试是否成功报错解决办法&#xff1a;下载linux模拟器wsl&#xff1a;双击打开docker重新打开cmd&#xff0c;输入命令&#xff0c;成功显示sever和clinet实操 开启 Hyper-V 和容器特性 控制面…...

环形链表相关的练习

目录 一、相交链表 二、环形链表 三、环形链表 || 一、相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据…...

C++ 提示对话框

头文件 #include<iostream>#include<cstdio> using namespace std; 函数格式 MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) 参数 hWnd &#xff1a;此参数代表消息框拥有的窗口。如果为NULL&#xff0c;则消息框没有拥有窗口。 lp…...

SprintBoot打包及profile文件配置

打成Jar包 需要添加打包组件将项目中的资源、配置、依赖包打到一个jar包中&#xff0c;可以使用maven的package&#xff1b;运行: java -jar xxx(jar包名) 操作步骤 第一步: 引入Spring Boot打包插件 <!--打包的插件--> <build><!--修改jar的名字--><fi…...

java面试-java集合

说说你如何选用集合&#xff1f; 需要键值对选用 map 接口下的集合&#xff0c;需要排序用 TreeMap, 不需要排序用 HashMap 不需要键值对仅存放元素则选择 Collection 下实现的接口&#xff0c;保证元素唯一使用 Set, 不需要则选用 List Collection 和 Collections 有什么区别…...

Node.js简介

客户端访问网页时向服务器端发送请求要访问服务器中的页面&#xff0c;服务器收到请求后向数据库中进行搜索&#xff0c;搜索到相关数据然后返回结果给客户端显示&#xff1b; 这个过程就类似于&#xff1a;客人&#xff08;客户端&#xff09;去饭馆&#xff08;服务端&#…...

每天学一点之Lambda表达式

Lambda表达式 思想导入&#xff1a; 函数式编程思想&#xff1a; 在数学中&#xff0c;函数就是有输入量、输出量的一套计算方案&#xff0c;也就是“拿什么东西做什么事情”。编程中的函数&#xff0c;也有类似的概念&#xff0c;你调用我的时候&#xff0c;给我实参为形参赋…...

Raft分布式共识算法学习笔记

1. Raft算法 Raft算法属于Multi-Paxos算法&#xff0c;它是在Multi-Paxos思想的基础上&#xff0c;做了一些简化和限制&#xff0c;比如增加了日志必须是连续的&#xff0c;只支持领导者、跟随者和候选人三种状态&#xff0c;在理解和算法实现上都相对容易许多 从本质上说&am…...

中介者模式

介绍 Java中介者模式(Mediator Pattern)是一种行为设计模式,它可以降低多个对象之间的耦合性,通过一个中介者对象来协调这些对象的交互. 在中介者模式中,多个对象之间的交互不是直接进行的,而是通过一个中介者对象来进行的.这个中介者对象封装了对象之间的交互逻辑,每个对象只…...

Kaggle赛题解析:Google手语识别

文章目录一、比赛前言信息二、比赛背景三、比赛任务四、评价指标五、数据描述六、解题思路一、比赛前言信息 比赛名称&#xff1a;Google - Isolated Sign Language Recognition 中文名称&#xff1a;帮助用户从PopSign游戏学习美国手语 比赛链接&#xff1a;https://www.ka…...

什么是ChatGPT?

目录前言一、什么是GPT&#xff1f;二、什么是ChatGPT&#xff1f;三、ChatGPT应用场景四、ChatGPT未来展望五、OpenAI介绍前言 3月3号&#xff0c;早上6:30就有人发消息给我&#xff0c;来问我有关GPT API的事件。 那是因为3月2号&#xff0c;OpenAI 发布了ChatGPT 3.5的开放…...

深入理解Zookeeper的ZAB协议

ZAB是什么ZAB&#xff08;Zookeeper Atomic Broadcast&#xff09;&#xff1a;Zookeeper原子广播ZAB是为了保证Zookeeper数据一致性而产生的算法&#xff08;指的是Zookeeper集群模式&#xff09;。它不仅能解决正常情况下的数据一致性问题&#xff0c;还可以保证主节点发生宕…...

opencv-图像几何处理

缩放 缩放只是调整图像的大小。为此&#xff0c;opencv提供了一个cv2.resize()函数&#xff0c;可以手动指定图像大小&#xff0c;也可以指定缩放因子。你可以使用任意一种方法调整图像的大小&#xff1a; import cv2 from matplotlib import pyplot as pltlogo cv2.imread(…...

[前端笔记030]vue之hello、数据绑定、MVVM、数据代理、事件处理、计算属性和监视属性

前言 本笔记参考视频&#xff0c;尚硅谷:BV1Zy4y1K7SH p1 -p25官网文档完善&#xff0c;本文只做笔记使用&#xff0c;官网下载vue的开发版和生产版或者使用CDN&#xff0c;并去谷歌商店下载开发插件 简介 组件化模式&#xff0c;提高代码复用率&#xff0c;更好维护声明式编…...

每天学一点之注解、元注解

注解 1、注解概述 定义&#xff1a; 注解&#xff08;Annotation&#xff09;&#xff0c;也叫元数据。与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面&#xff0c;用来对这些元素进行说明&#xff0c;注释。 作用分类&#…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制

目录 节点的功能承载层&#xff08;GATT/Adv&#xff09;局限性&#xff1a; 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能&#xff0c;如 Configuration …...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...