【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优化技巧…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...