C语言(字符和字符串函数)2

news2025/1/23 10:41:46

         Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,欢迎欢迎~~     

                                                💥个人主页:小羊在奋斗

                                                💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为一些学友们展示一下我的学习过程及理解。文笔、排版拙劣,望见谅。 

                                6、strcmp 的使用和模拟实现

                                7、strncpy、strncat 和 strncmp

                                8、strtok 的使用和模拟实现

                                9、strstr 的使用和模拟实现

                                10、strerror 函数的使用

6、strcmp 的使用和模拟实现

        6.1 strcmp 的用法

        其实对于 strcmp 函数我们并不陌生,在之前的学习中已经不止一次用到过。

        strcmp 函数的作用是比较两个字符串的大小,当结果是大于时返回一个正值,小于时返回一个负值,等于时返回0。所以 strcmp 函数的返回值是int类型,我们在使用字符串函数的时候一定要清楚每个函数的返回值是什么。

        要特别注意的是,strcmp 函数比较两个字符串比较的不是字符串的长度,而是对应位置字符的ASCII码值。 

      可以看到,当对应位置字符的ASCII码值前者大于后者时,strcmp 函数返回了1;当小于时,strcmp 函数返回了-1;当等于时,strcmp 函数返回了0。来看下面代码示例:

        这个代码有没有什么问题呢?其实,上面的代码在VS中是没有任何问题的,但是在其他编译器中可能就会发生错误。其中的原因在 strcmp 函数的返回值上,我们说当前面的字符串大于后面的字符串时返回一个正值,但这个正值可以是任意正值,而在VS上规定这个正值为1,但是在其他编译器上并不见得这个正值都为1。

        6.2 strcmp 的模拟实现

        有了前几个模拟实现字符串函数的经验,模拟 strcmp 函数难度也不是太大。 

#include <stdio.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}

int main()
{
	char str1[] = "abcdef";
	char str2[] = "abcijk";
	int ret = my_strcmp(str1, str2);
	printf("%d\n", ret);
	return 0;
}

        特别的,还可以简化成下面的形式。

7、strncpy、strncat 和 strncmp

        出了 strcpy、strcat 和 strcmp 外,C语言还提供了更加灵活的 strncpy、strncat 和 strncmp,它们算是前三者的升级版,使用起来更加灵活。以 strncpy 为例:

        可以看到 strncpy 相较于 strcpy 多了一个参数,用于指定拷贝多少个字符。另外两个也是类似。

        虽然它们的逻辑表面上看起来是一样的,但是 strcnpy 和 strncat 之间还是有一点差异的

 

 

        可以看到 strncpy 不会给目标字符串主动添加 ‘\0’,但 strncat 就会主动给目标字符串添加 ‘\0’,这是两个函数间的差异。 

        那既然有了 strncat 函数,我们就能弥补上一小节中未能实现字符串自己拼接到自己后面的遗憾了。

8、strtok 函数的使用      

        更多详细介绍请跳转阅读 —> strtok, strtok_s - cppreference.com   

         看了上面的介绍好像还是云里雾里的,我用通俗的话来解释一下。delim 指向一个字符串,定义了用作分隔符的字符集合;第一个参数指定一个字符串,它包含了0个或多个由delim字符串中的一个或多个分隔符分割的标记;strtok 函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(strtok 函数会改变被操作的字符串,所以被 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改);strtok 函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok 函数将保存它在字符串中的位置;strtok 函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记;如果字符串中不存在更多标记,则返回NULL指针。也就是说,只需要传递一次指向字符串的非空指针,剩下的都传空指针。

        上面的描述其实说的是  strtok 函数是一个过滤指定字符,提取出你想要的部分的函数。比如,有一个邮箱地址 18655404590@163.com,我们想要剔除其中的特殊字符 ‘@’ 和 ‘.’ ,提取出18655404590、163和com,那我们就可以使用 strtok 函数来实现。其中字符指针str指向目标字符串“18655404590@163.com”,delim 指向指定的分隔符“@、.”。

        但是,上面是我们事先知道字符串中有两个分隔符,所以写了三个打印函数,那如果我们不知道一个字符串中有多少个分隔符呢?这里可以用for循环来解决,之前我们在介绍for循环的文章中说过这么一句话,for循环通常用来解决循环次数未知的情况。

 

 9、strstr 的使用和模拟实现

        9.1 strstr 的使用

        更多详细介绍请跳转阅读 —> strstr - cppreference.com                简单来说,strstr 函数的作用是在一个字符串中查找另一个字符串,找到了就返回这个字符串第一次出现的起始地址,没找到就返回一个空指针。来看示例:

        9.2 strstr 的模拟实现

        模拟实现 strstr 函数之前,我们需要想清楚怎么在一个字符串中找另一个字符串是否存在呢?容易想到的是两个字符串通过指针解引用来一个一个的比较来判断是否存在一个相同的字符串,大致思路如下:

        (1)逐个字符地访问被查找的字符串,当访问到与目标字符串首字符相同的字符时记住这个可能的地址,方便后面返回;

        (2)当两个字符串的字符两两比较一直到目标字符串访问到 ‘\0’ 时说明找到了,返回之前记住的地址;

        (3)当被查找的字符串访问到 ‘\0’ 时说明被查找的字符串不存在,返回一个空指针;

        (4)综上,需要创建三个指针,其中两个指向被查找字符串,一个用来逐个访问字符,一个用来记住可能的地址,第三个指针指向目标字符串并且在改变了指针的指向后重新让其指向目标字符串的首地址。

#include <stdio.h>
#include <assert.h>

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = str1;//用于返回可能的地址
	if (*str2 == '0')//当目标字符串是空字符串时
	{
		return cur;
	}
	while (*cur != '\0')
	{   
		s1 = cur;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//找到了目标字符串
		{
			return cur;
		}
		cur++;
	}
	return NULL;//没找到
}

int main()
{
	char str1[] = "abcdddeab";
	char str2[] = "deab";
	char* ps = my_strstr(str1, str2);
	if (NULL == ps)
	{
		printf("不存在\n");
	}
	else
	{
		printf("%s\n", ps);
	}
	return 0;
}

10、 strerror 函数的使用

        更多详细介绍请跳转阅读 —> strerror, strerror_s, strerrorlen_s - cppreference.com

 

         简单地说,strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

        在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量 errno 来记录程序当前的错误码,只不过程序启动的时候 errno 是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码存放在 errno 中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的,strerror 函数就可以将错误对应的错误信息字符串的地址返回来。

         整数0~10对应的错误信息如下:

         再来举一个例子,其中涉及到一些我们之前还没学到的内容,请不要在意,主要是 strerror 函数的用法。

         C语言函数中还有一个函数和 strerror 函数的功能是相似的,它就是 perror 函数。来看一下它的介绍:

        它和 strerror 函数的区别在哪里呢?

        strerror 函数的功能是将错误码对应的错误信息的字符串的地址返回,而 perror 函数的功能是将 errno 中错误码对应的错误信息打印出来。那它是怎样打印的呢?perror 函数打印的规则是先打印字符指针s指向的字符串,再打印一个冒号和一个空格,然后打印错误码对应的错误信息。 

 

        可以看到上面 printf 函数和 perror 函数打印的内容是一样的。

        也就是说 perror == printf + strerror。我们可以根据自己的选择选用这两个函数。

        如果觉得我的文章还不错,请点赞、收藏 + 关注支持一下,我会持续更新更好的文章。  

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

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

相关文章

今日分享丨按场景定制界面

遇到问题 我们在写文档或者代码时&#xff0c;会遇到需要书写重复或者类似内容的情况。快捷的做法是&#xff1a;先复制粘贴此相似内容&#xff0c;再修改差异。那么开发人员在设计界面的时候&#xff0c;也会遇到同类型的界面有重复的特性&#xff0c;比如报销类型的单据&…

PostgreSQL常用插件

PostgreSQL 拥有许多常用插件&#xff0c;这些插件可以大大增强其功能和性能。以下是一些常用的 PostgreSQL 插件&#xff1a; 性能监控和优化 pg_stat_statements 1.提供对所有 SQL 语句执行情况的统计信息。对调优和监控非常有用。 2.安装和使用&#xff1a; pg_stat_k…

picoLLM:大模型的量化魔术师 上

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调重新阅读。而最新科技&#xff08;Mamba&#xff0c;xLSTM,KAN&#xff09;则提供了大模…

数字孪生在气象灾害防治中的重要贡献

数字孪生技术在气象灾害防治中正发挥着越来越重要的作用。数字孪生是指通过数字化方式在虚拟空间中构建与现实世界对应的虚拟模型&#xff0c;通过实时数据和模拟技术进行动态映射和交互。利用数字孪生技术&#xff0c;气象部门可以更高效、更精准地监测、预测和应对气象灾害&a…

四川景源畅信:抖音开店怎么做好运营?

在数字化时代的浪潮中&#xff0c;抖音作为一个流量巨大的社交平台&#xff0c;为许多商家提供了展示和销售产品的新舞台。但在这个充满竞争的平台上&#xff0c;如何做好店铺运营&#xff0c;吸引并留住顾客&#xff0c;成为了许多商家面临的挑战。接下来的内容将围绕如何在抖…

我与C++的爱恋:vector的使用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;我与C的爱恋 ​ 文章目录 一、vector的简单介绍二、vector的使用构造函数遍历容器对容器的操作vector 的增删查改 一、vector的简单介绍 vector是表示可变大小数组的序列容器 就像数组…

去噪扩散概率模型在现代技术中的应用:图像生成、音频处理到药物发现

去噪扩散概率模型&#xff08;DDPMs&#xff09;是一种先进的生成模型&#xff0c;它通过模拟数据的噪声化和去噪过程&#xff0c;展现出多方面的优势。DDPMs能够生成高质量的数据样本&#xff0c;这在图像合成、音频生成等领域尤为重要。它们在数据去噪方面表现出色&#xff0…

打开C语言常用的内存函数大门(二)—— memmove()函数 (内含memmove的讲解和模拟实现)

文章目录 1. 前言2. memmove()函数2.1 memmove()函数与memcpy()函数的差异2.2 memmove()函数的原型2.3 memmove()函数的使用案例 3. memmove()函数的模拟实现4. 总结 1. 前言 在之前&#xff0c;我向大家介绍了C语言中的一个常用的内存函数memcpy函数。如果你还没看的话&#…

算法(十一)贪婪算法

文章目录 算法简介算法概念算法举例 经典问题 -背包问题 算法简介 算法概念 贪婪算法&#xff08;Greedy&#xff09;是一种在每一步都采取当前状态下最好的或者最优的选择&#xff0c;从而希望导致结果也是全局最好或者最优的算法。贪婪算法是当下局部的最优判断&#xff0c…

【UnityShader入门精要学习笔记】第十六章 Unity中的渲染优化技术 (下)

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 减少需要处…

报表工具DataEase技术方案(一)

一、使用场景&#xff1a; 企业内部系统想要快速接入报表功能&#xff0c;但是局限于人力资源不足&#xff0c;不想沿用传统的前端后端开发模式&#xff0c;可以尝试使用开源报表工具 DataEase。 二、架构设计&#xff1a; 使用最简便的报表集成方式&#xff0c;通过DataEase…

越洗越黑”的Pandas数据清洗

引言 先来一个脑筋急转弯活跃一下枯燥工作日常&#xff0c;问&#xff1a;“什么东西越洗越黑&#xff1f;” 有没有猜到的&#xff1f;猜不到我告诉你吧&#xff01; 答案是“煤球”。那么这个脑机急转弯跟我们要讨论的话题有没有关系呢&#xff1f; 嗯是的&#xff0c;还是沾…

2024年大屏幕互动源码+动态背景图和配乐素材+搭建教程

2024年大屏幕互动源码动态背景图和配乐素材搭建教程 php宝塔搭建部署活动现场大屏幕互动系统php源码 运行环境&#xff1a;PHPMYSQL 下载源码地址&#xff1a;极速云

Leetcode刷题笔记7

69. x 的平方根 69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09; 假设求17的平方根 解法一&#xff1a;暴力解法 从1开始依次尝试 比如1的平方是1&#xff0c;2的平方是4...直到5的平方&#xff0c;25>17&#xff0c;所以一定是4点几的平方&#xff0c;所以等于4…

打家劫舍I 打家劫舍II (leetcode)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 打家劫舍Ihttps://leetcode.cn/problems/Gu0c2T/打家劫舍IIhttps://leetcode.cn/problems/PzWKhm/ 状态转移方程就是这样的&#xff1a; i位置选择偷f[i]&#xff1a;f[i] g[i-1] nums[i];i位置选择不偷g[i]&#xff1a;g…

C语言 指针——指针变量做函数参数:典型实例

目录 一个典型实例——两数互换 一个典型实例——两数互换 Errors

拓展虚拟世界边界,云手机可以做到吗

虚拟世界&#xff0c;AI&#xff0c;VR等词汇是21世纪最为流行的词汇&#xff0c;在科技背后&#xff0c;这些词汇的影响变得越来越大&#xff0c;已经走进了人们的世界&#xff0c;比如之前APPLE发布的vision pro&#xff0c;使人们能够更加身临其境的体验到原生os系统&#x…

存储 Bean 对象更加简单的方式

前置操作 如果是在 spring-config 中添加 bean 标签来注册内容&#xff0c;每个类都要弄一次就显得麻烦和臃肿了&#xff0c;对于 new 操作而言就没有什么优势了。因此 spring 就引入了注解操作来实现对 Bean 对象的存储。 配置扫描路径 想要将对象成功的存储到 Spring 中&…

【Linux系列】深入解析 `kill` 命令:Linux 下的进程管理利器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【每日力扣】32. 最长有效括号 416. 分割等和子集

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 32. 最长有效括号 给你一个只包含 ( 和 ) 的字符串&#xff0c;找出最长有效&#xff08;格式正确且连续&#xff09;括号 子串 …