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

devtools/2024/12/24 10:29:25/

在这里插入图片描述


一.字符分类函数

C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是ctype.h。

如图:

在这里插入图片描述

这些函数的使用方法非常类似,我们就讲解一个函数的事情,其他的非常类似:

1 int islower ( int c);

islower 是能够判断参数部分的c是否是小写字母的。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。

来看练习:

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述


二.字符转换函数

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

1  int tolower ( int c ); //将参数传进去的大写字母转小写
2  int toupper ( int c ); //将参数传进去的小写字母转大写

来看相关例子:

在这里插入图片描述

返回值是int,**返回的是转化成对应字符的ASCII值,**不要忘了包含头文件ctype.h。

关于上面我们举的例子,将小写转大写,是-32完成的效果,有了转换函数,就可以直接使用toupper函数。

在这里插入图片描述


三.strlen的使用和模拟实现

1 size_t strlen ( const char * str );

strlen函数的相关要求:

字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’10’)。
参数指向的字符串必须要以’\0’结束。
注意函数的返回值为size_t,是无符号的(易错)
strlen的使用需要包含头文件

该函数使用举例:

在这里插入图片描述

strlen函数工作原理:从给定的起始位置开始,向后统计\0之前的字符个数。

我们来看一个小知识点

在这里插入图片描述

为什么会打印出这样的结果?

因为strlen函数返回值是size_t类型的,两个size_t类型的值相减得到的值-3也是size_t类型的,size_t类型是无符号的整型,它的补码最高位1不会被当成符号位,所以-3就变成了特别大的正数值。

在这里插入图片描述

所以我们如果这样写代码就是坑了自己,我们可以直接相比来得到我们想要的。

在这里插入图片描述

或者强制类型转换一下

在这里插入图片描述

strlen函数的模拟实现

关于strlen函数的模拟实现有三种方式:

1.计数器 
2.指针 - 指针
3.递归的方式

我们来写代码实现这三种方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


四.strcpy的使用和模拟实现

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

strcpy函数的相关要求:

Copies the C string pointed by source into the array pointed by destination, including the terminating null
character (and stopping at that point).
源字符串必须以’\0’结束。
会将源字符串中的’\0’拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可修改。

在这里插入图片描述

举例:

在这里插入图片描述

该函数也会把要拷贝的字符串中的\0拷贝到目标函数中,我们来调试看:

在这里插入图片描述
在这里插入图片描述

我们要知道使用该函数拷贝字符串,源头字符串中必须要有\0,否则没办法拷贝。

在这里插入图片描述

在这里插入图片描述

拷贝的时候没有\0就不知道什么时候停下来,造成越界访问。所以该函数用于拷贝字符串,字符串中有\0结束标志。

还有就是我们要拷贝到的目标空间要足够大

在这里插入图片描述

拷贝到的目标空间不够大,造成越界访问,程序崩掉了。

目标空间必须可修改

在这里插入图片描述

在这里插入图片描述

我们这样写代码程序也会崩掉,p指向的空间里面存放的是常量字符串,它是不能被修改的。

我们来看strcpy的模拟实现:

在这里插入图片描述

优化一下

在这里插入图片描述

我们将表达式放到while循环判断的地方的时候,既可以赋值,赋值产生的结果又可以判断,这样的话\0也可以被拷贝过去了,又作为赋值结果结束条件。

strcpy函数的返回值类型是char*,strcpy返回的是目标空间的起始地址。我们再来改改模拟实现的strcpy函数。

在这里插入图片描述


五.strcat的使用和模拟实现

strcat函数的相关要求:

Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string
formed by the concatenation of both in destination.
源字符串必须以’\0’结束。
目标字符串中也得有,否则没办法知道追加从哪里开始。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。

简单来说:strcat函数是实现字符串的链接或追加。

在这里插入图片描述

在这里插入图片描述

举例:

在这里插入图片描述
在这里插入图片描述

通过上面的例子,可知strcat函数追加方式是:找到目标空间中的第一个\0,然后从这个\0的位置开始追加源头字符串,源头字符串的内容,包括\0都会追加到目标空间。

strcat函数的模拟实现

在这里插入图片描述

还有一个问题要注意一下:当我们用该函数自己给自己追加的时候,会造成死循环的问题。


六.strcmp的使用和模拟实现

strcmp函数的相关要求:

This function starts comparing the first character of each string. If they are equal to each other, it
continues with the following pairs until the characters differ or until a terminating null-character is reached.
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
那么如何判断两个字符串? 通过比较两个字符串中对应位置上字符ASCII码值的大小。

在这里插入图片描述

strcmp函数是用来比较两个字符串的大小,对应位置上的字符进行比较,根据ASCII值的大小。

例子:

在这里插入图片描述
在这里插入图片描述

strcmp函数的模拟实现

在这里插入图片描述

我们再来看另一种写法:

在这里插入图片描述


七.strncpy 函数的使用

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

strncpy函数的相关要求:

Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

在这里插入图片描述

通过比较我们知道该函数比strcpy函数多了个参数,该参数指定了你最多要拷贝多少个字符。

我们用例子来理解,比如指定想要拷贝字符串前五个字符。

在这里插入图片描述

在这里插入图片描述

但是如果我们源头字符串只有两个,却指定拷贝5个会怎么样呢?

在这里插入图片描述
从上面例子可知:如果源字符串不够,该拷贝的拷贝过来,其他的用\0补齐,也就是补零。


八.strncat 函数的使用

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

strncat函数的相关要求:

Appends the first num characters of source to destination, plus a terminating null-character. (10字符串的前num个字符追加到destination指向的字符串末尾,再追加一个\0字符)。
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果source 指向的字符串的长度小于num的时候,只会将字符串中到\的内容追加到destination指向的字符串末尾)。

在这里插入图片描述

我们通过比较也发现strncat函数和strcat函数参数也是差了一个。这个参数是指定追加源头字符串多少个字符。

在这里插入图片描述

另一个例子:

在这里插入图片描述

在这里插入图片描述

从上面例子我们可知把两个x追加来之后又加上了一个\0。我们再来看如果指定的个数大于源头字符串字符个数,该怎么样追加呢?

在这里插入图片描述

我们看到它并没有像strncpy函数一样凑齐5个,不够补\0。


九.strncmp函数的使用

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

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

在这里插入图片描述

该strncmp函数比strcmp函数多出来的参数是指定最多比较的字符个数。

举例:

在这里插入图片描述


十.strstr的使用和模拟实现

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

strstr函数的相关要求:

Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1. (#ZO?符串str2在字符串str1中第一次出现的位置)。
The matching process does not include the terminating null-characters, but it stops there. (不包含\0字符,以\作为结束标志)。

在这里插入图片描述

strstr函数作用是:在一个字符串中,找一个子字符串,找第一次出现的位置。从上面我们来看该函数的参数部分,它的意思是:在str1指向的字符串中找str2指向的字符串第一次出现的位置。

该strstr函数如果找到了,就返回第一次出现的地址,如果找不到,就返回NULL。

我们来举例使用一下该函数:

在这里插入图片描述

strstr函数的模拟实现

const char* my_strstr(const char* str1, const char* str2)
{const char* s1 = str1;const char* s2 = str2;const char* cur = str1; // cur指针记可能的开始匹配的位置if (*str2 == '\0')//当str2是空字符串时,直接返回str1return str1;while (*cur){//完成一次匹配s1 = cur;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return cur;cur++;}return NULL;}int main()
{char arr1[] = "abcdefabcdef";char arr2[] = "def";const char* ret = my_strstr(arr1, arr2);if (ret == NULL)printf("找不到\n");elseprintf("找到了:%s\n", ret);return 0;
}

当str2是\0时,这是特殊的情况,以后写代码的时候,根据自己需求来决定该返回什么。

我们再来优化一下

在这里插入图片描述


十一.strtok函数的使用

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

sep参数指向一个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回NULL指针。

我们来看该函数的使用场景

在这里插入图片描述

把分隔符(如上面的:@ . )的分开的字符串提取出来。

来看例子:

在这里插入图片描述

但是我们一般用该函数的时候不会把源头字符串的数组名传过去,因为该数组会被改变破坏掉,我们会创建另一个数组拷贝一份来使用。

在这里插入图片描述

当我们第二次调用strtok函数第一个参数为NULL,它会从上一次保存的位置向后找,如上面的例子,第二次调用会返回y的地址,把 . 改成\0。

在这里插入图片描述
在这里插入图片描述

我们一般不用这样形式写代码,请看下面代码:

在这里插入图片描述


十二.strerror函数的使用

1 char* strerror ( int errnum);

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

在这里插入图片描述

上面我们只是把错误码对应的错误信息打印出来看一下,我们再来看它的使用场景:

在这里插入图片描述

关于fopen函数已经讲解过了,就不再说了。产生的错误码放到了errno变量中了,不要忘记包含它的头文件,如果有多个错误码,再次发生错误产生的错误码会把上一次的错误码覆盖掉了,所以要及时的检测。

perror的使用

在这里插入图片描述

在这里插入图片描述

打印的时候,先打印你传的字符串,然后它会在字符串后面加上冒号和一个空格,再打印错误信息。


这篇有点多,关于C语言的内容还剩一篇就结束了,加油!!!

在这里插入图片描述


http://www.ppmy.cn/devtools/144951.html

相关文章

SCOPE: Optimizing Key-Value Cache Compression in Long-context Generation

基本信息 📝 原文链接: https://arxiv.org/abs/2412.13649👥 作者: Jialong Wu, Zhenglin Wang, Linhai Zhang, Yilong Lai, Yulan He, Deyu Zhou🏷️ 关键词: large language models, Key-Value Cache📚 分类: 机器学习 摘要 …

二进制分析的新兴趋势:塑造安全的移动应用

在当今快速发展的数字世界中,保障移动应用的安全性变得尤为重要。随着移动技术的广泛应用,安全性需求也日益增强。二进制分析作为确保移动应用安全和合规性的重要手段,通过对已编译的应用进行深入分析,能够发现源代码中难以察觉的…

《计算机组成及汇编语言原理》阅读笔记:p48-p81

《计算机组成及汇编语言原理》学习第 4 天,p48-p81 总结,总计 34 页。 一、技术总结 1.CISC vs RISC p49, complex instruction set computing For example, a complex instruction set computing (CISC) chip may be able to move a lar…

Android Jetpack LiveData源码解析

1. LiveData简介 LiveData是Android Jetpack架构组件中的一个核心类,它是一个可观察的数据持有者类。LiveData的设计初衷是为了简化UI组件的生命周期管理,它具有生命周期感知特性,确保只有在应用程序组件(如Activity、Fragment&a…

Farfalle - 开源的AI搜索引擎

2600 Stars 232 Forks 32 Issues 4 贡献者 Apache-2.0 License Python 语言 代码: https://github.com/rashadphz/farfalle 主页: Farfalle 演示: Farfalle 更多AI开源软件:https://www.aiinn.cn/sources FarFalle 是一款开源的AI搜索引擎项目,类似Perpl…

golang, go sum文件保证下载的依赖模块是一致的

在 Go 编程语言中,go.sum 文件是 Go 模块管理的一部分,主要用于记录模块的校验信息(模块版本的校验和)。它的设计目标是确保模块的完整性和安全性,解决以下关键问题: 1. 确保模块版本的一致性 go.sum 文件…

传统网络架构与SDN架构对比

传统网络采用分布式控制,每台设备独立控制且管理耗时耗力,扩展困难,按 OSI 模型分层,成本高、业务部署慢、安全性欠佳且开放性不足。而 SDN 架构将控制平面集中到控制器,数据转发由交换机负责,可统一管理提…

springboot中使用gdal将表中的空间数据转shapefile文件

springboot中使用gdal将表中的空间数据转shapefile文件 代码: // 样本导出-将样本表导出为shapefile,复制样本shp文件到临时目录下 sampleDir是文件夹pathpublic void setYbShapeFile(Yb yb, File sampleDir) {// 创建 前时项 和 后时项 文件夹File y…