【C语言】——字符串函数的使用与模拟实现(下)
【C语言】——字符串函数的使用与模拟实现(下)
- 前言
- 五、长度受限类字符串函数
- 六、 s t r s t r strstr strstr 函数
- 6.1、函数功能
- 6.2、函数的使用
- 6.3、函数的模拟实现
- (1)解题思路
- (2)代码实现
- 七、 s t r t o k strtok strtok 函数
- 7.1、函数功能
- 7.2、函数的使用
- 八、 s t r e r r o r strerror strerror 函数
- 8.1、函数功能
- 8.2、函数的使用
- 九、 p e r r o r perror perror 函数
前言
上一篇文章:【C语言】——字符串函数的使用与模拟实现(上)中,我曾详细介绍了: s t r s t r strstr strstr、 s t r c p y strcpy strcpy、 s t r c a t strcat strcat、 s t r c m p strcmp strcmp 这四个函数及其模拟实现,接下来,让我们继续学习字符串相关的函数吧。
五、长度受限类字符串函数
5.1、 s t r n c p y strncpy strncpy 函数
功能:将源字符串的前 n u m num num 个字符拷贝到目标字符串中
- 如果源字符串长度小于 n u m num num,则拷贝完源字符创后,在目标空间后面
追加\0
,直到 n u m num num 个。 - 如果源字符串长度大于 n u m num num,则在拷贝完源字符串前 n u m num num 个字符后,末尾
不会
自动补 ‘\0’
5.2、 s t r n c a t strncat strncat 函数
功能:将源字符串的前 n u m num num个字符追加至目标字符串的末尾
- 如果源字符串长度大于 n u m num num,追加前 n u m num num 个字符并在后面
补'\0'
- 如果源字符串长度小于 n u m num num,追加整个源字符串并
补'\0'
。(只补一个
,不会一直补到 n u m num num 个)
5.3、 s t r n c m p strncmp strncmp 函数
功能:比较 s t r 1 str1 str1 和 s t r 2 str2 str2 的前 n u m num num 个字符,如果相等就继续往后比较,最多比较 n u m num num 个字符,如果提前发现不一样,提前结束,大的字符所在的字符串大于另外一个
,如果 n u m num num 个字符都相等
,就返回 0
。
六、 s t r s t r strstr strstr 函数
6.1、函数功能
功能:查找字符串 s t r 1 str1 str1 中是否包含字符串 s t r 2 str2 str2 的内容,如果有,返回第一次出现的地址,如果没有,返回空指针。
需要注意的是:字符串的比较匹配不包含 ‘\0’,以 ‘\0’ 作为结束标志。
6.2、函数的使用
#include<stdio.h>
#include<string.h>int main()
{char str1[] = "This is a simple string";char* str2;str2 = strstr(str1, "simple");printf("%s\n", str2);for (int i = 0; i < strlen("simple"); i++){printf("%c", str2[i]);}printf("\n");str2 = strstr(str1, "are");printf("%s\n", str2);return 0;
}
运行结果:
6.3、函数的模拟实现
(1)解题思路
( i ) (i) (i) 首先,我们来看最简单的情况:在 “ a b c d e f abcdef abcdef” 中找 “ c d e cde cde”
- 我们先来看上左图: s t r 1 str1 str1 和 s t r 2 str2 str2 指向两个字符串起始位置,是我们传入的值,这里我额外创建指针 c p cp cp 变量,用指针 c p cp cp 来遍历 s t r 1 str1 str1 数组。
- 看上右图:当指针 c p cp cp 指向字符 ‘ c c c’ 时,发现字符 ‘ c c c’ 与 s t r 2 str2 str2的首字符相同。
为进一步确认
, c p cp cp 与 s t r 2 str2 str2同时遍历
后面的字符,每遍历一次,相比较一次。当 s t r 2 str2 str2 遍历完字符串,比较结束,发现所比较的字符全部相等,即找到 s t r 1 str1 str1 中的 s t r 2 str2 str2。
上面的思路看起来是可行的,但是还是存在这很大的问题:
- 函数要求的是返回地址,也就是返回上面 ‘ c c c’ 字符的地址,可是 c p cp cp 指针跑后面去了,怎么返回他的地址呢?
- 想象一下,当 c p cp cp 开始比较时,与 s t r 2 str2 str2 的前几个字符是相等的,但后面不相等,这时是不是
又要从‘c’的下一个字符重新开始比较
,但是 c p cp cp 与 s t r 2 str2 str2都跑后面去
了,还怎么找到下一个字符呢?
( i i ) (ii) (ii) 下面,我们来考虑复杂一点的情况:在 “ a b b b c d f abbbcdf abbbcdf” 中找 “ b b c bbc bbc”
鉴于上述情况出现的两种问题,我们再额外创建两个指针变量 s 1 s1 s1 与 s 2 s2 s2,他们负责实现字符的逐个比较
,而 c p cp cp 与 s t r 2 str2 str2用于记录开始比较的起始位置
。这样,当 s 1 s1 s1 与 s 2 s2 s2 只有部分相等时,依然可以找到下一个字符重新开始比较
( i i i ) (iii) (iii) 再看最后一种情况:如果找不到怎么办?例如:在 “ a b b b c abbbc abbbc” 中找 “ b b c c bbcc bbcc”
其实,中不到的情况的解决思路与第二种情况时一样
的,不同的是,当 c p cp cp 遍历完
整个 s t r 1 str1 str1 字符串(即 c p cp cp 指向 \0)还没找到时,即 s t r 1 str1 str1 中不存在 s t r 2 str2 str2 字符串,返回空指针
(2)代码实现
char* my_strstr(const char* str1, const char* str2)
{//创建指针变量:cp、s1、s2//因为并不知道什么时候开始比较,s1、s2先置空const char* cp = str1;const char* s1 = NULL;const char* s2 = NULL;//特殊情况:当str2为空时,返回整个str1if (str2 == NULL){return (char*)str1;}//循环,当cp指向‘\0’时,退出,表面没找到while (*cp){//进入逐个比较if (*cp == *str2){//给s1、s2赋值,让他们进行比较s1 = cp;s2 = str2;//如果他们相等,并且不等于‘\0’比较继续while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}//退出比较时,表明遇到不一样的字符//这时有两种情况//退出后,当s2指向‘\0’时,表明成功找到//当s2不是指向‘\0’,表示并不是要找的字符串if (*s2 == '\0'){return (char*)cp;}}cp++;}//整个循环结束,表明没找到,返回空指针return NULL;}
七、 s t r t o k strtok strtok 函数
7.1、函数功能
函数功能:将 s t r str str 字符串 以字符 d e l i m i t e r s delimiters delimiters 作为分隔符
,分割成若干段
。
- s t r str str 参数表示
要分割的字符串
- d e l i m i t e r s delimiters delimiters 参数表示
分隔符
,分隔符可以是多个
- s t r t o k strtok strtok 函数找到 s t r str str 中的下一个标记,并将其用 \0 结尾,返回一个
指向这段字符串的指针
- s t r t o k strtok strtok 函数会
改变
被操作的字符串,所以在使用 s t r t o k strtok strtok 函数切分的字符串一般都是临时拷贝
的内容,并且可以被修改
- s t r t o k strtok strtok 函数的第一个参数不为NULL时,函数将
找到
s t r str str 中的第一个标记
, s t r t o k strtok strtok 函数将保存它在字符串中的位置
- s t r t o k strtok strtok 函数的第一个参数为NULL,函数将在同一个字符串中
被保存的位置开始
,查找下一个标记
- 如果字符串
不存在更多的标记
,则返回NULL指针
7.2、函数的使用
像 happy@qq.com,现在我想将 happy、qq、com 这三段单独提取出来,这时就可以使用 s t r t o k strtok strtok函数
#include<stdio.h>
#include<string.h>int main()
{char arr1[] = "happy@qq.com";char arr2[30];const char* sep = "@.";strcpy(arr2, arr1);char* ret = NULL;ret = strtok(arr2, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);return 0;
}
运行结果:
可以看到, s t r t o k strtok strtok 函数很奇怪,只有第一次调用他是传的是要切割的字符串 a r r 2 arr2 arr2,之后调用都是传 NULL。
这是因为该函数每一次调用该函数都把当前找的这个标记的结束位置记住
,这样下次再调用该函数就能从上次保存的位置开始找下一个标记
当第四次调用该函数时,因为已经找到结束位置
,因此函数返回空指针。
注:这里只是示范,实际上是不允许这样打印的
当然,上面的代码有很大的改进空间
,因为我们往往不知道有几个分隔符,这时我们可以用一种巧妙的写法
#include<stdio.h>
#include<string.h>int main()
{char arr1[] = "happy@qq.com@happy@qq.com";char arr2[30];const char* sep = "@.";strcpy(arr2, arr1);char* ret = NULL;for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}
我们来分析一下for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep))
这个循环:
- 首先是初始化部分
ret = strtok(arr2, sep)
:将strtok(arr2, sep)
的值传给 r e t ret ret 变量 - 接着是判断部分
ret != NULL
:当 r e t ret ret 不为空时,循环继续,即打印该段字符串;当返回值为空,表示已经分割完字符串,循环结束 - 最后是调整部分
ret = strtok(NULL, sep)
:将strtok(NULL, sep)
的返回值赋给 r e t ret ret 变量 - 这个代码巧妙在 s t r t o k strtok strtok 函数要求第一次传的是字符串,而之后传的是NULL,这里完美运用了 f o r for for 循环的特点:
先初始化,并且初始化只执行一次,调整语句执行多次
。
运行结果:
八、 s t r e r r o r strerror strerror 函数
8.1、函数功能
功能:把参数部分错误码对应的错误信息的字符串地址返回来
在不同的系统和 C 语言标准库中都规定了一些错误码
,一般放在 < e r r n o . h errno.h errno.h> 这个头文件中说明。
C语言程序启动时就会使用一个全面的变量
e r r n o errno errno 来记录程序当前的错误码,只不过程序启动时 e r r n o errno errno 是 0,表示没有错误
。
当我们在使用标准库中的函数的时候发生了某种错误
,就会将对应的错误码,放在errno中
,而一个错误码的数字是整数,因此很难理解是什么意思,所以每个错误码都是有对应的错误信息的。 s t r e r r o r strerror strerror 函数就可以将错误对应的错误信息字符串的地址返回
。
8.2、函数的使用
我们打印 0 − 10 0-10 0−10 这些错误码所对应的信息
#include<errno.h>
#include<string.h>
#include<stdio.h>int main()
{int i = 0;for (i = 0; i <= 10; i++){printf("%s\n", strerror(i));}return 0;
}
运行结果:
再比如:我们以读的方式打开一个不存在的文件,让其返回错误信息
#include<errno.h>
#include<string.h>
#include<stdio.h>int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (NULL == pFile){printf("Error opening file unexist.ent: %s\n", strerror(errno));}return 0;
}
运行结果:
九、 p e r r o r perror perror 函数
功能: p e r r o r perror perror 函数相当于 p e i n t f + s t r e r r o r peintf+strerror peintf+strerror,它会打印完参数本分的字符串内容
后,再打印一个冒号
和一个空格
,再打印错误信息
。
例如:
#include<errno.h>
#include<string.h>
#include<stdio.h>int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (NULL == pFile){perror("Error opening file unexist.ent");}return 0;
}
运行结果:
好啦,本期关于部分字符串函数的介绍及模拟实现就介绍到这里啦,希望本期博客能对你有所帮助,更多关于字符串的函数还请收看下一期。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!
相关文章:

【C语言】——字符串函数的使用与模拟实现(下)
【C语言】——字符串函数的使用与模拟实现(下) 前言五、长度受限类字符串函数5.1、 s t r n c p y strncpy strncpy 函数5.2、 s t r n c a t strncat strncat 函数5.3、 s t r n c m p strncmp strncmp 函数 六、 s t r s t r strstr strstr 函数6.1、函…...

mac安装nvm详细教程
0. 前提 清除电脑上原有的node (没有装过的可以忽略)1、首先查看电脑上是否安装的有node,查看node版本node -v2、如果有node就彻底删除nodesudo rm -rf /usr/local/{bin/{node,npm},lib/node_modules/npm,lib/node,share/man/*/node.*}2、保证自己的电脑上有安装git,不然下载n…...

上线流程及操作
上节回顾 1 搜索功能-前端:搜索框,搜索结果页面-后端:一种类型课程-APIResponse(actual_courseres.data.get(results),free_course[],light_course[])-搜索,如果数据量很大,直接使用mysql,效率非常低--》E…...

MobX入门指南:快速上手状态管理库
一、什么是MobX MobX 是一个状态管理库,它可以让你轻松地管理应用程序的状态,并且可以扩展和维护。它使用观察者模式来自动传播你的状态的变化到你的 React 组件。 二、安装及配置 安装 MobX 和 MobX-React:你可以使用 npm 或 yarn 安装这…...
技术洞察:Selenium WebDriver中Chrome, Edge, 和IE配置的关键区别
综述 webdriver.EdgeOptions(), webdriver.ChromeOptions(), 和 webdriver.IeOptions() 都是 Selenium WebDriver 的配置类,用于定制化启动各自浏览器的设置。它们分别对应 Microsoft Edge,Google Chrome,和 Internet Explorer 浏览器。 每…...
使用自定义OCR提升UIE-X检测效果:结合PaddleOCR和UIE模型进行文档信息提取
在实际应用中,识别文档中的特定信息对于许多任务至关重要,例如发票识别、表格信息提取等。然而,由于文档的多样性和复杂性,传统的光学字符识别(OCR)技术可能无法准确识别文档中的信息。为了解决这个问题&am…...
题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog con…...

.net反射(Reflection)
文章目录 一.概念:二.反射的作用:三.代码案例:四.运行结果: 一.概念: .NET 反射(Reflection)是指在运行时动态地检查、访问和修改程序集中的类型、成员和对象的能力。通过反射,你可…...

P1278 单词游戏 简单搜索+玄学优化
单词游戏 传送门 题目描述 Io 和 Ao 在玩一个单词游戏。 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致。 游戏可以从任何一个单词开始。 任何单词禁止说两遍,游戏中只能使用给定词典中含有…...

软考 - 系统架构设计师 - 数据架构真题
问题 1: (相当于根据题目中提到的 4 点,说一下关系型数据库的缺点) (1).用户数量的剧增导致并发负载非常高,往往会达到每秒上万次读写请求。关系数据库应付每秒上万次的 SQL 查询还勉强可以,但是应付上万…...
Ubuntu22.04下opencv4.9.0环境的搭建
目录 1、更新系统包列表:2、安装依赖项:3、下载 OpenCV 源代码:4、编译和安装 OpenCV:5、配置环境变量:6、测试1、更新系统包列表: 在终端中执行以下命令,以确保系统包列表是最新的: sudo apt update2、安装依赖项: 安装构建 OpenCV 所需的依赖项: sudo apt inst…...

Flask如何在后端实时处理视频帧在前端展示
怎么样在前端->选择视频文件->点击上传视频后->后端实时分析上传的视频->在前端展示后端分析结果(视频,文本) ↓ 咱们先看整看整体代码,有个大概的印象。 Flask后端代码 cljc车流检测Demofrom pytz import timezon…...

04-15 周一 GitHub仓库CI服务器actions-runner和workflow yaml配置文档解析
04-15 周一 GitHub仓库CI服务器配置过程文档 时间版本修改人描述2024年4月15日10:35:52V0.1宋全恒新建文档2024年4月17日10:33:20v1.0宋全恒完成github actions CI的配置和工作流配置文件解读文档的撰写 简介 一些基础概念 前提知识 仓库介绍 地址镜像介绍https://github.…...

论文笔记:SmartPlay : A Benchmark for LLMs as Intelligent Agents
iclr 2024 reviewer评分 5688 引入了 SmartPlay,一种从 6 种不同游戏中提取的基准 衡量LLM作为智能体的能力 1 智能代理所需的能力 论文借鉴游戏设计的概念,确定了智能LLM代理的九项关键能力,并为每项能力确定了多个等级: 长文…...

搜维尔科技:【工业仿真】煤矿安全知识基础学习VR系统
产品概述 煤矿安全知识基础学习VR系统 系统内容: 煤矿安全知识基础学习VR系统内容包括:下井流程(正确乘坐罐笼、班前会、井下行走注意事项、工作服穿戴、入井检身及人员清点、下井前准备工作、提升运输安全);运煤流程…...
线程和进程的区别(面试)
线程和进程的区别 进程和线程的区别线程的优点 进程和线程的区别 1. 进程是系统进行资源分配和调度的一个独立单位,线程是程序执行的最小单位. 2. 进程有自己的内存地址空间,线程只独享指令流执行的必要资源,如寄存器和栈. 3. 由于同一进程的各线程共享内存和文件资源,可以不通…...
抓取电商产品数据的方法|电商平台商品详情数据|批量上架|商品搬家|电商封装API数据采集接口更高效安全的数据采集
大量级电商数据采集时使用电商API接口有以下优势: 1. 数据准确性:通过电商API接口获取数据,可以保证数据的准确性和实时性,避免了手动采集可能出现的错误和延迟。 2. 自动化采集:API接口可以实现自动化的数据获取和更…...
关联规则Apriori算法
1.前置知识 经典应用场景:购物车商品的关联规则。 符号表示: I代表项集,项是可能出现的值,例如购物车中能有尿布、啤酒、奶粉等,I{尿布、啤酒、奶粉},尿布是项 K代表I中包含的项的数目,上面的k3 事…...

书生·浦语大模型全链路开源体系-第4课
书生浦语大模型全链路开源体系-第4课 书生浦语大模型全链路开源体系-第4课相关资源XTuner 微调 LLMXTuner 微调小助手认知环境安装前期准备启动微调模型格式转换模型合并微调结果验证 将认知助手上传至OpenXLab将认知助手应用部署到OpenXLab使用XTuner微调多模态LLM前期准备启动…...
HTML优化SEO
在网站开发中,除了关注设计和用户体验,SEO(搜索引擎优化)也是提升网站流量和可见度的关键。合理的HTML结构和元素运用能够帮助搜索引擎更好地理解页面内容,从而提高搜索排名。以下是一些基于HTML的SEO优化技巧…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...