C语言------字符函数和字符串函数

news2024/11/27 8:39:10

在学习编程的过程中,我们会经常会遇到一些字符和字符串,为了方便操作字符和字符串,C语言标准库中就提供了一系列函数。那么,接下来就学习下这些函数。

1. 字符分类函数

C语言中有一系列的函数是专门做字符分析的,也就是判断一个字符属于什么类型的字符的。

这些函数的使用都需要包含一个头文件 ctype.h

上图就是字符类函数的一些种类。

这些函数的使用方法非常类似,我们就以一个函数为例。

int main()
{
	int ret1 = islower('c');
	int ret2 = islower('A');
	printf("ret1 = %d\n", ret1);
	printf("ret2 = %d\n", ret2);

	return 0;
}

islower函数 是一个能判断参数部分是否为小写字母的函数。

通过返回值来说明是否为小写字母,如果是小写字母,就返回一个非0的整数,如果不是小写字母,就返回数字0。 

2. 字符转换函数

C语言提供了两个字符转换函数:

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

多说不用,直接上一道例题体会体会。

练习:将一个字符串的小写字母转换成大写字母,其他字符不变。

int main()
{
	char arr[] = "hello man";
	int i = 0;
	while (arr[i])
	{
		if (islower(arr[i]))
		{
			arr[i] = toupper(arr[i]);
		}
		i++;
	}
	printf("%s", arr);
	return 0;
}

上面代码就是通过 toupper 这个函数将字符串中的小写字母转换成大写代码的例子。

运行如下 

3. strlen的使用和模拟实现 

size_t strlen ( const char * str );

1.strlen函数是用来计算一个字符串大小的库函数,不过它计算的是 ‘\0’ 前面的大小,不包括 ‘\0’,所以用strlen来计算大小是以 ‘\0’ 为结束标志的。

2.参数指向的字符串必须要以 '\0' 结束。

3.注意strlen函数的返回值是 size_t 类型的。这是一个易错点。

4. strlen 的使用需要包含其头文件 <string.h>

为什么说第3点是一个易错点呢?直接上代码

#include <stdio.h>
#include <string.h>
int main()
{
 const char* str1 = "abcdef";
 const char* str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 } 
 else
 {
 printf("srt1>str2\n");
 }
 return 0;
}

上面这段代码运行结果是什么呢?

相信很多人就立马猜出打印 str1>str2。 到底是不是呢?

运行代码,发现并不是我们猜想的那样。到底是为什么呢?

哦,原来是strlen函数的返回值类型为size_t的原因,size_t 是无符号整形的意思,两个无符号整形的相减的结果还是无符号整形的,尽管原来的结果是负数,但被强制转换成了size_t类型的,结果中带有的负号就不再算是符号位了,也就不算是一个 负数了。这就导致了运行结果的不同。

strlen函数的3中模拟实现

1. 计算器类型

int my_strlen(const char * str)
{
 int count = 0;
 assert(str);
 while(*str)
 {
 count++;
 str++;
 }
 return count;
}

2,递归类型

int my_strlen(const char * str)
{
 assert(str);
 if(*str == '\0')
 return 0;
 else
 return 1+my_strlen(str+1);
}

3.指针-指针类型

int my_strlen(char *s)
{
 assert(str);
 char *p = s;
 while(*p != ‘\0’ )
 p++;
 return p-s;
}

4.strcpy的使用和模拟

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

strcpy函数的作用是将一个字符串里面的内容复制到另一个字符串里面。 如上形式,就是将source里面字符串里的内容复制到destination字符串。

使用时注意事项

1. 源字符串必须以 '\0' 结束。

2.strcpy不仅会将字符串的内容复制到另一个函数,也会将 '\0' 一同复制过去。

3.目标空间必须可修改,如果目标空间是一个常量,就无法使用strcpy函数。

4.目标空间必须足够大,有确保能保存复制过来的内容。

strcpy的模拟实现

实现模拟之前。我们要清楚strlen函数是将字符串里面的内容一个一个复制过来的。

void my_strcpy( char* dest,  char* soc)
{
	while (*soc != '\0')
	{
		soc++;
		dest++;
	}
	*dest = *soc; // 将 '\0' 复制过来

}
int main()
{
	char arr1[] = "xxxxxxx";
	char arr2[20] = "abcd";
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

我们也可以简化成以下版本 

void my_strcpy( char* dest,  char* soc)
{
	while (*dest++==*soc++)
	{
      ;
	}
}
int main()
{
	char arr1[] = "xxxxxxx";
	char arr2[20] = "abcd";
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

简化版本也会将 '\0' 复制过去的,虽然++的优先级比 * 好高,但它是后置++,所以是先用完指定数据在进行++,也就是先对dest和soc进行解引用之后,再分别++,由于while()循环只有条件为真时才能进行,所以当soc一直++到 '\0' 时,赋值给dest时,条件刚好为0,循环终止,dest 也刚好被赋值 '\0' , 也就将arr2中的 '\0' 复制过去了。

以 %s 的形式打印时,也是以 '\0' 为终点的。 

运行如下

5.strcat的使用和模拟

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

strcat()函数是用来拼接2个字符串的函数。

使用strcat的注意事项

1. 源字符串必须要以 '\0' 结尾。

2. 目标空间也必须要有  ‘\0' 结尾,否则不知道从哪里开始拼接。

3. 目标空间要有足够大的空间来存储源字符串复制过来的内容。

4. 目标空间必须是可修改的空间。

我们还是直接通过代码感受

int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

这段代码是将arr2里面的内容拼接到arr1里面。

运行代码如下图

 

通过上面图片可知,arr2的内容已经成功拼接到arr1里面了。

模拟实现strcat函数

模拟之前,先大概清楚下strcat()函数是如何实现拼接的。

首先,我们要找到目标空间的 '\0' ,确定了开始拼接的位置,然后再一个一个将要拼接的内容拼接到目标空间。

了解这个,开始实现代码

void my_strcat(char* dest, const char* soc)
{
	assert(dest && soc);
	//找到目标空间的 \0
	while (*dest)
	{
		dest++;
	}
	//接着开始实现复制,复制就和前面的strcmp的一摸一样了
	while ((*dest++ = *soc++))
	{
		;
	}

}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

 

6. strcmp的使用和模拟

int strcmp ( const char * str1, const char * str2 );

strcmp是用来比较2个字符串的大小的。 

两个字符串的比较原理

两个字符串相互比较时,两个字符串中的相应字符会一个一个进行比较,如上图,直到遇到两个不同的字符,这时,那个字符的ASCII值大,对应的字符串就大。如上图,c的ASCII值大于b的,则下面的字符串大。

strcmp是有返回值的。

标准规定:

1.当第一个字符串 小于  第二个字符串时,返回一个小于0的值。

2.当第一个字符串 等于 第二个字符串时,返回0.

3.当第一个字符串 大于 第二个字符串时,返回一个大于0的值。

照惯例,上代码

int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	int ret=strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

 

由于arr1字符串小于arr2字符串,所以ret为一个小于0的值。

模拟实现strcmp()函数

int my_strcmp(char* arr1, char* arr2)
{
	while (*arr1 == *arr2)
	{
		if (*arr1 = *arr2)
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	if (*arr1 > *arr2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "abcd";
	int ret=my_strcmp(arr1, arr2);
	printf("ret=%d", ret);
	return 0;
}

也可以简化成

int my_strcmp(char* arr1, char* arr2)
{
	while (*arr1 == *arr2)
	{
		if (*arr1 = *arr2)
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	return *arr1 - *arr2;
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "abcd";
	int ret=my_strcmp(arr1, arr2);
	printf("ret=%d", ret);
	return 0;
}

因为是通过字符串里面的字符一个一个进行比较,所以想到用到了while()循环。

7.strncpy的使用

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

其实strncpy的使用和strcpy差不多,多了一个参数 num。

意思是将源字符串 num 个字符复制到目标空间。

注意事项

如果源字符串的长度小于num个,则会一直给目标空间补'\0',直到达到num个。 

8.strncat的使用

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

strncat的用法和strcat差不多,也是多了个参数num。

意思是将源字符串num个字符拼接到目标空间去,并追加一个 '\0' 。

注意事项

 如果源字符串的长度小于num,则只会将 '\0' 前面的内容拼接到目标空间

9.strncmp的使用

strncmp的用法和strcmp差不多,也是多了个参数num。

意思是⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0。

10.strstr的使用和模拟

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

strstr()函数是用来在一个字符串中寻找另一个字符串。

如果有则返回开始匹配的地址,如没有则返回NULL。

老样子,上代码

int main()
{
	char arr1[20] = "abbbbhicd";
	char arr2[] = "abb";
	char* ret=strstr(arr1, arr2);
	printf("%s", ret);
	return 0;
}

如上图,在arr1字符串中寻找arr2字符串,由于当第一个字符匹配,再继续往后找时,就找到了abb,所以就将在arr1中开始匹配的地址返回,也就是将arr1中的a的地址返回。

运行结果如下

模拟实现strstr()

有几种情况我们要讨论一下

第一种情况是比较简单的,当发现第一个字符不匹配时,让arr1继续往后走,接着进行匹配就行了。

这种情况是最复杂的。

我们发现第一个字符不匹配时,让arr1+1,指向b,接着匹配,b和b匹配了, arr1和arr2一起进行加1,但发现匹配过程中有匹配不了了,所以这时我们要重新匹配,所以要让arr1和arr2共同返回开始匹配的位置,但是arr1和arr2已经在后面了,不在匹配时的位置了。

因此我们想到要用2个指针分别记录arr1中开始匹配的位置和arr2的起始地址。

 

如上图所示,用一个指针纪录开始匹配的位置,这样当我们匹配到半路失败时,可以返回的开始匹配地址。

char* my_strstr(const char* arr1,const char* arr2)
{
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = arr1;
	if (*arr2 == '\0')
	{
		return (char*)arr1;
	}
	while (*cur)
	{
		s1 = cur;
		s2 = arr2;
		while (*s1 !='\0' && *s2!='\0' && * s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cur;
		}
		cur++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbcefg";
	char arr2[] = "bbc";
	char* ret=my_strstr(arr1, arr2);
	printf("%s", ret);
	return 0;
}

11. strtok函数的使用

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

1.解释参数的意思

1.1 sep参数指向一个字符串,定义了一个用作分隔符的集合。

1.2.  第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的
标记。
2. strtok的用法原理
1. strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容
并且可修改。)
2. strtok函数的第⼀个参数不为NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串
中的位置。
3. strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标
记。
4. 如果字符串中不存在更多的标记,则返回 NULL 指针。
老样子,上代码
int main()
 {
 char arr[] = "192.168.6.111";
 char* sep = ".";
 char* str = NULL;
 for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
 {
   printf("%s\n", str);
 }
 return 0;
}

12.strerror的使用

1 char * strerror ( int errnum );
 strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说
明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码, 只不过程序
启动的时候errno是0,表⽰没有错误 ,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会
讲对应的错误码,存放在errno中, ⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个
错误码都是有对应的错误信息的 。strerror函数就可以将错误对应的错误信息字符串的地址返回。
int main()
{
 int i = 0;
 for (i = 0; i <= 10; i++) {
 printf("%s\n", strerror(i));
 }
 return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

网络七层模型之会话层:理解网络通信的架构(五)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

飞天使-k8s知识点28-kubernetes散装知识点5-helm安装ingress

文章目录 安装helm添加仓库下载包配置创建命名空间安装 安装helm https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gztar -xf helm-v3.2.3-linux-amd64.tar.gzcd linux-amd64mv helm /usr/local/bin修改/etc/profile 文件&#xff0c;修改里面内容,然后重新启用export PATH$P…

java回溯算法笔记

回溯算法综述 回溯用于解决你层for循环嵌套问题&#xff0c;且不剪枝的回溯完全等于暴力搜索。 回溯算法模板https://blog.csdn.net/m0_73065928/article/details/137062099?spm1001.2014.3001.5501 组合问题 “不含重复元素”“不可重复使用”&#xff08;startindex i1&…

虚拟机体验 mac、Linux、Windows,老游戏和软件再也没有兼容问题

安装虚拟机 下载好 VMwareWorkstation Pro 后运行安装程序&#xff0c;根据流程完成安装&#xff1b; 勾选许可协议&#xff0c;点击「下一步」&#xff1b; 这里注意更改安装路径&#xff0c;最好选择 C 盘以外的其他磁盘&#xff0c;选择好后点击「下一步」&#xff1b; 这里…

2024/3/30面试题的总结

1.南京某公司 1.Java的几种基本数据类型&#xff1f;分别是多少字节&#xff1f; byte&#xff0c;8bit 1字节 char&#xff0c;16bit 2字节 short&#xff0c;16bit 2字节 int&#xff0c;32bit 4字节 float&#xff0c;32bit 4字节 long&#xff0c;64bit 8字节 doubl…

C++——vector类及其模拟实现

前言&#xff1a;前边我们进行的string类的方法及其模拟实现的讲解。这篇文章将继续进行C的另一个常用类——vector。 一.什么是vector vector和string一样&#xff0c;隶属于C中STL标准模板库中的一个自定义数据类型&#xff0c;实际上就是线性表。两者之间有着很多相似&…

Ubuntu系统设置静态固定IP保姆级教程

1、查看网络接口信息 ifconfig 首先需要确认要设置固定IP的网络接口。在大多数情况下&#xff0c;这通常是ens33 2、查看路由网关信息 route -n # 查看打印 路由表 网关地址 3、备份文件 为了防止防止出现意外问题。Ubuntu中的网络配置文件通常存储在/etc/netplan/目录下&…

Linux:详解TCP报头类型

文章目录 温习序号的意义序号和确认序号报文的类型 TCP报头类型详解ACK: 确认号是否有效SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段FIN: 通知对方, 本端要关闭了PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走RST: 对方要求重新建立连接; 我们把携带RST标识的称…

uniapp实现列表动态添加

1.效果图&#xff1a; 2.代码实现&#xff1a; 这里没有用uniapp提供的uni-list控件 <template> <view id"app"> <!-- 这里为了让标题&#xff08;h&#xff09;居中展示&#xff0c;给h标签设置了父标签&#xff0c;并设置父标签text-…

【零基础C语言】文件操作

目录 理解文件操作 什么是文件 程序文件 数据文件 文件名字 二进制文件和文本文件 文件的打开和关闭 文件的打开和关闭操作 实验1&#xff0c;打开一个文件并且输入26个字母 打开读取文件text.txt ,并且将它拷贝进text_cpy.txt 使用 fputs 和 fgets 函数 使用 fprintf函…

IDEA MyBatisCodeHelper Pro最新版(持续更新)

目录 0. 你想要的0.1 包下载0.2 使用jh 1. 功能介绍2. 下载安装2.1 在idea中插件市场安装2.2 在jetbrains插件市场下载安装 3. 简单使用3.1 创建一个SpringBoot项目3.2 配置数据库3.3 一键生成实体类、mapper 0. 你想要的 0.1 包下载 测试系统&#xff1a;Windows&#xff08…

el-table 合计行的一直计算的问题。

前端只有打印日志之后&#xff0c;才发现有计算在反复执行&#xff0c;导致浏览器崩溃。并不是每一列都是这个问题&#xff0c;当然输入不同值后&#xff0c;不知为何会触发如此多次。 . 在开发环境&#xff0c;他会触发几百次getSummaries,生产环境直接崩溃 合计行的代码如下…

入围中国大模型 + 知识管理最佳案例 15 强,杭州悦数 x 中国船舶项目收获认可!

近期&#xff0c;由国内知名的数字化研究与服务机构沙丘社区发布的《2024 中国“大模型知识管理”最佳实践案例 15 强》新鲜出炉&#xff0c;杭州悦数科技有限公司助力中国船舶集团有限公司第七〇八研究所打造的行业方案“基于图和多级智能体的动态排障知识问答系统”榜上有名。…

数据结构之二叉树由浅入深(四)

目录 题外话 正题 第一题 第一题思路 第一题代码详解 第二题 第二题思路 第二题代码详解 第三题 第三题思路 第三题代码及详解 第四题 第四题思路 第四题代码及详解 第五题 第五题思路 第五题代码及详解 题外话 本来昨天就想写完这篇文章,怎么样是不是很大胆?…

力扣124---二叉树的最大路径和(DFS,Java)

目录 题目描述&#xff1a; 思路描述&#xff1a; 代码&#xff1a; 题目描述&#xff1a; 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一…

在Arduino IDE中使用文件夹组织源文件和头文件

在Arduino IDE中使用文件夹组织源文件和头文件 如果你是一名Arduino爱好者&#xff0c;你可能会发现随着项目的复杂度增加&#xff0c;代码的管理变得越来越困难。在Arduino IDE中&#xff0c;你可以通过使用文件夹来更好地组织你的源文件和头文件&#xff0c;使得代码更加清晰…

标定系列——预备知识-OpenCV中与标定板处理相关的函数(四)

标定系列——预备知识-OpenCV中与标定板处理相关的函数&#xff08;四&#xff09; 说明记录棋盘格圆网格 说明 记录了OpenCV中与标定板处理相关的函数用法 记录 棋盘格 圆网格

Python 妙用运算符重载——玩出“点”花样来

目录 运算符重载 主角点类 魔法方法 __getitem__ __setitem__ __iter__ __next__ __len__ __neg__ __pos__ __abs__ __bool__ __call__ 重载运算符 比较运算符 相等 不等 ! 大于和小于 >、< 大于等于和小于等于 >、< 位运算符 位与 & 位…

这样使用ChatGPT,效率翻倍不是梦!四大秘诀公开

随着ChatGPT技术的不断革新&#xff0c;它在我们日常工作中扮演着越来越重要的角色。那么&#xff0c;我们该如何利用ChatGPT来解决工作难题呢&#xff1f; Q1&#xff1a;想要迅速获得ChatGPT的帮助&#xff0c;我们应如何提出问题&#xff1f; 以下是几条高效提问的建议&…

关于v114之后的chromedriver及存放路径

使用selenium调用浏览器时&#xff0c;我一直调用谷歌浏览器&#xff0c;可浏览器升级后&#xff0c;就会再次遇到以前遇到过的各种问题&#xff0c;诸如&#xff1a;1、怎么关闭浏览器更新&#xff1b;2、去哪儿下载chromedriver&#xff1b;3、114版本之后的驱动去哪儿下载&a…