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

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...