字符函数 和 字符串函数 的使用与模拟

news2024/11/15 13:53:37

前言:在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,接下来我们就学习⼀下这些函数。

目录

1. 字符函数

1.1 字符分类判断函数

1.2 字符转换函数

1.3 练习

2. 字符串函数

2.1 常用函数的 使用和模拟实现

1. strlen函数【计算字符串长度】​​​​​​​

2. strcpy函数【拷贝字符串】

3. strcat函数【拼接字符串】

4. strcmp函数【比较两个字符串大小】

5. strchr函数【在字符串中找一个字符】

6. strstr函数【在字符串中找一段字符】

2.2 其他字符串函数的 使用规则

7. strncpy函数

8. strncat函数

9. strncmp函数

10. strrchr函数

11. strtok函数

12. strerror函数 与 perror函数


1. 字符函数

C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。 这些函数的使⽤都需要包含⼀个头⽂件是 <ctype.h>

1.1 字符分类判断函数

这11个字符函数的函数原型,(1)除了名字不同,(2)它们的返回值都是int(且都是0或1),(3)参数表中也只有一个int型的形参

比如:

函数原型:int  islower(int c);

作用:如果输入c的ascii值属于a~z,那么返回值为1,否则返回值为0。

1.2 字符转换函数

C语⾔提供了2个字符转换函数:(只有2个)

函数原型:

int tolower ( int c );         //将参数传进去的⼤写字⺟转⼩写

int toupper ( int c );         //将参数传进去的⼩写字⺟转⼤写

tupper函数的模拟实现:

int my_toupper(int c)
{
	if (c >= 'a' && c <= 'z')
	{
		c = c - 32;
	}
	return c;
}

1.3 练习

写⼀个代码,将字符串中的⼩写字⺟转⼤写,其他字符不变:

int main()
{
	int i = 0;
	char str[] = "Test String.\n";
	char c;
	while (str[i])
	{
		c = str[i];
		if (islower(c))
			c = toupper(c);
		putchar(c);
		i++;
	}
	return 0;
}

2. 字符串函数

C语音中也有一系列的字符串函数,使用时需要包含头文件<string.h>

补充:下面的模拟实现中我用了assert断言,保证传入的多个字符串地址不是NULL,使用assert要包含头文件<assert.h>

2.1 常用函数的 使用和模拟实现

1. strlen函数【计算字符串长度】

函数原型:

1.   size_t  strlen ( const char * str );

作用:获取字符串长度。

使用规则:

  • strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包含 '\0' )。
  •  字符串以 '\0' 作为结束标志,参数指向的字符串必须要以 '\0' 结束
  •  注意函数的返回值为size_t,是⽆符号的( 易错 )

补充:sizeof 对于字符\0也会计算,而strlen不会。比如字符串“hello\0w”,sizeof计算的结果是8(别忘了w后面还有\0),而strlen计算的结果是5。

strlen的模拟实现:

strlen有3种方法可以模拟实现:

版本1

strlen--“计算器累计”版
int my_strlen1(const char* str)			 
{
	assert(str);
	int count = 0;
	char* p = str;
	while (*p)
	{
		count++;
		p++;
	}
	return count;
}

const修饰的原因:

保证了:不能通过解引用*str对原字符串进行修改

版本2

strlen--“指针-指针”版
int my_strlen2(const char* str)				
{
	assert(str);
	char* p = str;
	while (*p)
		p++;
	return p - str;
}

版本3

strlen--“函数递归”版
int my_strlen3(const char* str)				
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen3(str + 1);
}

函数递归也可以写成这样:

int my_strlen3(const char* str)				
{
	return *str=='\0' ? 0 : 1+my_strlen3(str+1);  
}

2. strcpy函数【拷贝字符串】

函数原型:

1.      char* strcpy(char * destination, const char * source );

作用:把字符串source的内容复制到字符串destination中。

使用规则:

  • source是源字符串,源字符串必须以 '\0' 结束。 
  • 会将源字符串中的 '\0' 也拷⻉到⽬标空间。 
  • ⽬标空间必须足够⼤,以确保能存放源字符串。 
  • ⽬标空间必须可修改。

strcpy的模拟实现:

char* my_strcpy(char* dest, const char* src)			
{
	assert(dest && src);
	char* ret = dest;

	while (*dest++ = *src++);	//会赋值为'\0'后再判断
	return ret;
}

while表达式的解析:

(1)先对两个指针进行+1操作

(2)然后对两边+1前的地址值进行解引用操作

(3)再把src所指向的内容赋值给dest

(4)最后对+1后的*dest检查是否等于'\0'(数值上,'\0'就等于0)

为了方便理解,可以写成这样:

while(*src != '\0')

{

        *dest = *src;

        src++;

        dest++;
}

3. strcat函数【拼接字符串】

函数原型:

1.      char* strcat(char * destination, const char * source ); 

作用:将一个字符串source追加到另一个字符串destination的末尾

使用规则:

  • 源字符串必须以 '\0' 结束。 
  • 会将源字符串中的 '\0' 拷⻉到⽬标空间。 
  • ⽬标空间必须⾜够⼤,以确保能存放源字符串。 
  • ⽬标空间必须可修改。

strcat的模拟实现:

char* my_strcat(char* dest, const char* src)			
{
	assert(dest && src);
	char* ret = dest;

	while (*dest)
	{
		dest++;
	}
	while (*dest++ = *src++);	//会赋值为'\0'后再判断

	return ret;
}

解析:

(1)第一个while循环,让指针dest指向目标字符串的结尾'\0'处。

(2)从dest指向的\0处开始拼接,并把\0覆盖掉。

(3)第二个while循环与strcpy的拷贝一样。

4. strcmp函数【比较两个字符串大小】

函数原型:

1.      int strcmp(const char *srt1, const char *str2);

作用:比较str1与str2的大小

使用规则:

  • str1⼤于str2,则返回⼤于0的数字 ◦
  • str1等于str2,则返回0 ◦
  • str1小于str2,则返回小于0的数字 ◦
  • 比较的本质1:⽐较两个字符串中对应位置字符ASCII码值的大小
  • 比较的本质2:比较出第1次不相同的两个字母,如果都相同才返回0。

strcmp的模拟:

int my_strcmp(const char* str1, const char* str2)			
{
	assert(str1 && str2);
	while (*str1 && *str2 && *str1 == *str2 )
	{
		str1++;
		str2++;
	}

	return *str1 - *str2;
}

其实也可以写成这样:

int my_strcmp(const char* str1, const char* str2)			
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

在“*str1==*str2”的前提下,如果满足*str1==‘\0’,那么也满足*str2==‘\0’。此时整个字符串已经比较完了,并没有不同的字符,所以返回0。

5. strchr函数【在字符串中找一个字符】

函数原型:

1.     char *strchr(const char *str, int c);

作用:在一个字符串中查找给定字符的第一个匹配之处

使用规则:

  • str是要查找的字符串,c是要查找的字符(输入时要acsii的值)
  • 从字符串的左边开始查找。
  • 如果找到第一个与c对应的字符,则返回该字符的地址(指针)。
  • 如果没有,则返回NULL

strchr的模拟实现:

char* my_strchr(const char* str, int c)					
{
	assert(str);
	char* pos = NULL;
	while (*str)
	{
		if (*str == c)
		{
			pos = str;
			break;
		}
		str++;
	}
	return pos;
}

如果没有找到与c一样的字符,那么pos仍然为NULL,此时返回pos就是返回NULL。

6. strstr函数【在字符串中找一段字符】

函数原型:

1.     char * strstr ( const char * str1, const char * str2);

作用:在一个字符串中查找另一个字符串的首次出现

使用规则:

  • str1是被检索的字符串,str2是查找表字符串。(在str1中找str2)
  • 在字符串str1中查找字符串str2的首次出现,并返回其地址。
  • 如果没有,则返回NULL

strstr的模拟实现:

char* my_strstr(const char* str1, const char* str2)			
{
	assert(str1 && str2);
	char *pos = NULL, *start = str2;
	//str2什么也没有
	if (!*str2)
		return pos;
	//str2有字符串
	while (*str1)
	{
		pos = str1;
		str2 = start;
		while (*str2 && *str1 && *str1++ == *str2++);

		if (*str2 == '\0')
			return pos;

		str1 = pos+1;
	}
	return NULL;
}

解析:

(1)str1根据pos复位:str1在与str2匹配的时候,会往后走。如果匹配失败,则str1要回到pos的位置,并从pos+1的位置重新匹配如果匹配成功,此时pos就是我们想要的位置

(2)str2根据start复位:str1在与str2匹配的时候,str2也会往后走。当要重新匹配时,str2要要回到起始位置重新匹配

2.2 其他字符串函数的 使用规则

7. strncpy函数

函数原型:

 char* strncpy(char* destination, const char* source, size_t num);

使用规则:

  • 保证destination足够长
  • 复制字符串source中的前num个字符 (从序号0到序号num-1)
  • 如果num大于source的字符串长度,那么多出几个字符,就补上几个\0,直到写入总数 num 个字符为止

8. strncat函数

函数原型:

 char* strncat(char* destination, const char* source, size_t num);

使用规则:

  • 保证destination足够长
  • 将 source 的前 num 个字符拼接到 destination(序号0到num-1)
  • 如果num大于source的长度,则source有多大就拼接多少,不会用\0补充

9. strncmp函数

函数原型:

 int strncmp(const char* str1, const char* str2, size_t num);

使用规则:

  • 比较str1和str2的前num个字符。(返回值的规则与strcmp一样)
  • 如果在第num-1个字符之前已经首次出现了不同的字符,就结束比较并返回比较的结果。
  • 如果str1与str2相等,且num比它们长不会再继续比较并返回0。(0表示两个字符串相等)

10. strrchr函数

函数原型:

 char* strrchr(char* str, int character);

使用规则:

  • 查找与character相同的字符
  • 从右边开始,向左边查找
  • 找到右边首次出现的相同字符后,返回该处的地址(指针)
  • 如果没有,则返回NULL

11. strtok函数

函数原型:

 char * strtok ( char * str, const char * sep);

使用规则:

  • 作用:按分隔符对字符串进行分割(每次只能分割一段
  • str是要被分割的字符串,sep是分隔符的字符集合
  • 第一次分割:此时strtok函数的参数str不为NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串中的位置
  • 每次分割完,该处的分隔符都会被制成\0来做成标记(改变了原字符串),然后返回⼀个指向这个标记的指针。
  • 后面的分割:此时strtok函数的参数str为NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记。
  • 完全分割后:如果字符串中不存在更多的标记,则返回 NULL 指针

注意:strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷贝的内容并且可修改

代码演示:

运行结果:

上面这个代码有2个语句重复出现了4次,我们可以用for循环来代替:这也是strtok的正确使用格式

	char* ps = NULL;
	for (ps = strtok(str, sep); ps != NULL; ps = strtok(NULL, sep))
	{
		printf("%s\n", ps);
	}

运行结果:

12. strerror函数 与 perror函数

函数原型: char * strerror ( int errnum );

作用:strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

包含头文件:<string.h><errno.h>

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

我们打印⼀下0~10这些错误码对应的信息:

#include<string.h>
#include<errno.h>
int main()
{
	int i = 0;
	for (i = 0; i <= 10; i++) {
		printf("错误%d:%s\n", i, strerror(i));
	}
	return 0;
}


strerror函数多用于文件操作的打开检查

例如:

int main()
{
	FILE* pFile;
	pFile = fopen("123", "r");
	if (pFile == NULL)
	{
		printf("错误原因: %s\n", strerror(errno));
	}
	return 0;
}

如果使用perror函数,可以缩减成这样:

int main()
{
	FILE* pFile;
	pFile = fopen("123", "r");
	if (pFile == NULL)
	{
		perror("错误的原因:");
	}
	return 0;
}

perror函数使用前要包含头文件<errno.h>

perror的原型:

1.     void perror(const char *s);

perror的作用:

  • 直接打印错误信息
  • 功能上,相当于是printf函数与strerror函数的结合。

本期分享结束,感谢大家的支持Thanks♪(・ω・)ノ

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

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

相关文章

Sui主网升级至V1.33.2

其他升级要点如下所示&#xff1a; #19404&#xff1a; 启用对等节点的共识轮次探测。 #19119&#xff1a; 无符号整数现在支持.to_string()方法&#xff0c;例如10u8.to_string()等同于 b”10".to_string()。 GraphQL #18774&#xff1a; 为GraphQL引入.move名称解…

Vue3.0组合式API:依赖注入provide和inject实现跨层组件的通信

1、Prop 逐级透传问题 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一棵巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据…

数字源表测试IC芯片电性能方案

芯片测试作为芯片设计、生产、封装、测试流程中的重要步骤&#xff0c;是使用特定仪器&#xff0c;通过对待测器件DUT(DeviceUnderTest)的检测&#xff0c;区别缺陷、验证器件是否符合设计目标、分离器件好坏的过程。其中直流参数测试是检验芯片电性能的重要手段之一&#xff0…

JAVA国际版同城货运新纪元货拉拉货运车系统小程序源码

&#x1f69a;国际货运新风尚&#xff0c;同城搬家轻松享 —— 货拉拉货运车系统&#xff0c;全球互联新体验&#x1f30d; &#x1f310;【开篇&#xff1a;跨越国界的货运新篇章】&#x1f310; 在这个全球化的时代&#xff0c;无论是跨国企业还是个人需求&#xff0c;都渴…

Java通信协议——UDP通信协议,模拟聊天室(完整详解,附有代码)

UDP通信协议&#xff0c;模拟聊天室 需求说明 实现客户咨询问题&#xff0c;客服人员答复问题 分析 咨询时&#xff0c;客户是发送方&#xff0c;客服人员是接收方 答复时&#xff0c;客服人员是发送方&#xff0c;客户是接收方&#xff0c;实现思路和咨询时相同 当客户端输入 …

【5G QoS】详解5G QoS端到端工作机制

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G技术研究。 博客内容主要围绕…

大田上的路径跟踪论文汇总

文章目录 2022Path tracking control method and performance test based on agricultural machinery pose correction&#xff08;Computers and Electronics in Agriculture&#xff09;An optimal goal point determination algorithm for automatic navigation of agricult…

4款AI生成PPT工具推荐,提升工作效率

在如今的工作环境中&#xff0c;PPT制作是许多技术人员不可避免的任务&#xff0c;尤其是在汇报、展示技术方案、以及项目进展时。随着AI技术的快速发展&#xff0c;使用AI生成PPT成为了提高效率的一种新趋势。本文将介绍几款适合程序员、技术人员的AI生成PPT工具&#xff0c;帮…

如何用 HAproxy 实施高可用部署 | OceanBase 实践

背景介绍 最近&#xff0c;我们部署了Oceanbase数据库&#xff08;以下简称OB&#xff09;&#xff0c;并将部分业务迁移至OB中运行。在部署过程中&#xff0c;我们虽然配置了3个OBProxy&#xff0c;但没有为它们设置高可用配置&#xff0c;应用被固定到某一个OBProxy 上&…

通信工程学习:什么是POS无源光分配器

POS&#xff1a;无源光分配器 POS&#xff08;Passive Optical Splitter&#xff0c;无源光分配器&#xff09;是无源光网络&#xff08;Passive Optical Network, PON&#xff09;中的一个重要组成部分&#xff0c;它位于光线路终端&#xff08;OLT&#xff09;和光网络单元&a…

基于Spring Boot的能源管理系统+建筑能耗+建筑能耗监测系统+节能监测系统+能耗监测+建筑能耗监测

介绍 建筑节能监测系统是基于计算机网络、物联网、大数据和数据可视化等多种技术融合形成的一套节能监测系统。 系统实现了对建筑电、水、热&#xff0c;气等能源、资源消耗情况的实时监测和预警、动态分析和评估&#xff0c;为用户建立了科学、系统的节能分析方法&#xff0c…

你天天用微服务还不知道心跳检测机制是什么?

目录标题 1. 心跳检测机制概述2. 心跳检测的具体实现2.1 服务注册与发现示例&#xff1a;Eureka 2.2 心跳包的格式2.3 超时机制 3. 实战中的心跳检测3.1 服务发现与注册中心3.2 定时任务与超时机制3.3 集群管理与协调3.4 故障隔离与恢复 4. 监控与告警5. 具体示例&#xff1a;Z…

制作一个rabbitmq-sdk

目录结构 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">&l…

VR全景摄影制作中的常见问题及解决方案

随着VR全景摄影技术的普及&#xff0c;越来越多的摄影师和企业开始尝试使用这种方式来展示产品、场景或服务。虽然VR全景摄影有着强大的视觉表现力和沉浸式体验&#xff0c;但在制作过程中也会遇到各种挑战。为了帮助大家更好地掌握VR全景摄影的制作技巧&#xff0c;今天给分享…

STM32 单片机最小系统全解析

STM32 单片机最小系统全解析 本文详细介绍了 STM32 单片机最小系统&#xff0c;包括其各个组成部分及设计要点与注意事项。STM32 最小系统在嵌入式开发中至关重要&#xff0c;由电源、时钟、复位、调试接口和启动电路等组成。 在电源电路方面&#xff0c;采用 3.3V 直流电源供…

【Bug解决】Nacos启动成功,但却无法访问(提示:无法访问此网站,192.168.10.88的响应时间过长)

项目场景&#xff1a; 在虚拟机上通过Docker创建Nacos容器&#xff0c;已经创建成功&#xff0c;查看Nacos启动日志也是成功。但通过端口号加8848/nacos&#xff08;如&#xff1a;http://IP:8848/nacos&#xff09;无法访问到Nacos管理页面。 愿意分析一&#xff1a; 先检查好…

MyISAM引擎介绍

文章目录 特点适用场景不足锁机制表级锁的类型锁的获取和释放锁的等待队列 示例共享锁排他锁READ LOCAL MyISAM是MySQL的一种存储引擎&#xff0c;它以其简单性和高速度而著称。在早期的MySQL版本中&#xff0c;MyISAM广泛使用&#xff0c;尤其是在那些以读操作为主的应用场景中…

Parallels Desktop 20(Mac虚拟机) v20.0.0 for Mac 最新破解版(支持M系列)

Parallels Desktop 20 for Mac 正式发布&#xff0c;完全支持 macOS Sequoia 和 Windows 11 24H2&#xff0c;并且在企业版中引入了全新的管理门户。 据介绍&#xff0c;新版本针对 Windows、macOS 和 Linux 虚拟机进行了大量更新&#xff0c;最大的亮点是全新推出的 Parallels…

6款好用的电脑监控软件推荐|2024电脑监控软件干货整理!

电脑监控软件成为了企业管理中不可或缺的工具&#xff0c;这些软件不仅能够帮助企业实时监控员工的工作状态&#xff0c;还能有效提升团队效率和保障数据安全。 本文将为您推荐六款2024年值得一试的电脑监控软件&#xff0c;每款软件都有其独特的亮点和优势&#xff0c;适合不…

【Java-线程池】

目录 什么是线程池&#xff1a; 线程池七大参数&#xff1a; 参数详细介绍&#xff1a; 1.核心线程数&#xff1a; 2.最大线程数&#xff1a; 3.线程存活时间&#xff1a; 4.时间单位&#xff1a; 5. 阻塞工作队列&#xff1a; 6.线程工厂&#xff1a; 7.拒绝策略&am…