【C语言】字符函数和字符串函数--超详解

前言:

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

1. 字符分类函数

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

这些函数的使⽤⽅法⾮常类似

int islower ( int c );

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

练习:

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

#include <ctype.h>
int main()
{int i = 0;char str[] = "Test String.\n";char c;while (str[i]){c = str[i];if (islower(c)){c -= 32;}putchar(c);i++;}return 0;
}

 运行结果:

2. 字符转换函数

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

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

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

上⾯的代码,我们将⼩写转⼤写,是-32完成的效果,有了转换函数,就可以直接使⽤ tolower 函 数。

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;
}

运行结果:

3. strlen 的使⽤和模拟实现

size_t strlen ( const char * str );

字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包 含 '\0' )。

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

注意函数的返回值为 size_t,是⽆符号的( 易错 )

strlen的使⽤需要包含头⽂件(#include <string.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("str1>str2\n");}return 0;
}

strlen的模拟实现:

方法1:

我们通过创建一个临时变量count来统计个数

int my_strlen(const char* str)
{int count = 0;assert(str);while (*str){count++;str++;}return count;
}int main()
{char* str = "abcdef";int ret = my_strlen(str);printf("%d\n", ret);return 0;}

方法2: 

使用递归来计算字符串的长度。递归的终止条件是当当前字符是空字符 ('\0') 时返回 0,否则返回 1 加上递归调用 my_strlen(str+1)的结果。这种递归方法会逐层深入字符串,并在回溯时计算字符串的长度。

//不能创建临时变量计数器
int my_strlen(const char * str)
{assert(str);if(*str == '\0')return 0;elsereturn 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 指向的位置,直到遇到源字符串的结束符 '\0'。复制结束后,destination 指向的字符串将与source指向的字符串相同

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

会将源字符串中的 '\0' 拷⻉到⽬标空间。

⽬标空间必须⾜够⼤,以确保能存放源字符串。

⽬标空间必须可修改。

strcpy模拟实现:

我们来分析一下strcpy函数中不就是把第二个参数'\0'之前的内容拷贝给第一个参数吗?然后再把'\0'拷贝到第一个参数里面吗?

char* my_strcpy(char *dest, const char*src)
{char *ret = dest;assert(dest != NULL);assert(src != NULL);while((*dest++ = *src++)){;}return ret;
}

5. strcat 的使⽤和模拟实现

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

strcat这个函数就是追加的意思,将第二个参数的字符串追加到第一个参数的字符串的后面。

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

⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始

⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。

⽬标空间必须可修改。

模拟实现strcat函数:

char *my_strcat(char *dest, const char*src)
{char *ret = dest;
assert(dest != NULL);assert(src != NULL);while(*dest){dest++;}while((*dest++ = *src++)){;}return ret;
}

字符串⾃⼰给⾃⼰追加,如何?

不要这样,这样会导致死循环程序崩溃的,自己给自己追加的时候尽量不要使用strcat万一他功能不能满足自己给自己追加呢。

自己追加自己不就把自己的'\0'改了吗?那还怎么停止,这样就导致了死循环

6. strcmp 的使⽤和模拟实现

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

两个字符串的内容不能直接进行比较,需要使用strcmp(如果直接比较,比较的是地址首元素的地址)

第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字 ◦

第⼀个字符串等于第⼆个字符串,则返回0

第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字

那么如何判断两个字符串?

⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩

strcmp函数的模拟实现:

strcmp函数不就是让两个字符串的内容进行一个一个的进行比较吗?我们通过解引用让他们进行比较如果相等地址++一直循环下去如果遇到'\0'了还一直相等就放回0,如果不相等了就跳出循环,直接返回现在所指的字符之差的数。

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

7. strncpy 函数的使用

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

destination 是目标字符串的指针,用于存储复制后的字符串。

source 是源字符串的指针,即要被复制的字符串。

num 是要复制的最大字符数,包括空字符。

这个函数的功能是将源字符串 source 中的最多 num 个字符复制到目标字符串 destination 中。如果 source 的长度小于 num,则目标字符串会被填充到 num 个字符用'\0凑够;如果 source 的长度大于或等于 num,则只复制 num 个字符,不会添加额外的空字符。

如果要拷贝8个字符不够就用'\0'凑够

int main()
{char str1[20] = { 0 };const char* str2 = "abcdef";strncpy(str1,str2,3);printf("%s", str1);return 0;
}

8. strncat 函数的使⽤

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

这个函数用于将源字符串 source 的最多 num 个字符连接到目标字符串 destination 的末尾。如果源字符串的长度小于 num,则会把有的字符拼接过去包括'\0,如果源字符串的长度大于或等于 num,则只会连接 num 个字符,并在目标字符串的末尾添加空字符。

需要注意的是,destination 必须具有足够的空间来容纳要连接的字符以及额外的空字符。否则,可能会发生缓冲区溢出的情况,导致未定义行为

int main()
{char str1[50] = "ghijk";const char* str2 = "abcdef";strncat(str1, str2, 2);return 0;
}

9. strncmp函数的使⽤

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

str1str2 分别是要比较的两个字符串的指针,num 是要比较的字符数。

函数会按顺序比较两个字符串的前 num 个字符。如果两个字符串在前 num 个字符内完全相同,则返回值为0;如果两个字符串在前 num 个字符内不同,则返回值为它们第一个不同字符的差值。差值是根据字符的 ASCII 值计算得出的。

int main()
{char str1[50] = "abc";const char* str2 = "abz";int ret = strncmp(str1, str2, 2);if (ret == 0) {printf("相同\n");}else if (ret < 0) {printf("str1 小于 str2\n");}else {printf("str1 大于 str2\n");}return 0;printf("%s", str1);return 0;
}

运行结果: 

10. strstr 的使⽤和模拟实现

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

strstr在一个字符串中查找另一个字符串,函数返回字符串str2在字符串str1中第⼀次出现的位置

字符串的⽐较匹配不包含 \0 字符,以 \0 作为结束标志

char* strstr(const char* str1, const char* str2)
{const char* s1 = NULL;const char* s2 = NULL;const char* cur = str1;if (*str2 == '\0')return(char*)str1;while (*cur){s1 = cur;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return (char *)cur;}cur++;}return(NULL);
}

11. strtok 函数的使⽤

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

sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合

第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记。

strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容 并且可修改。)

strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。

strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记。

如果字符串中不存在更多的标记,则返回 NULL 指针。

#include <stdio.h>
#include <string.h>
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 函数的使⽤

char * strerror ( int errnum );

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

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

#include <errno.h>
#include <string.h>
#include <stdio.h>
//我们打印⼀下0~10这些错误码对应的信息
int main()
{int i = 0;for (i = 0; i <= 10; i++) {printf("%s\n", strerror(i));}return 0;
}

在Windows11+VS2022环境下输出的结果如下:

No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input / output error
No such device or address
Arg list too long
Exec format error
Bad file descriptor
No child processes

举例:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL)printf ("Error opening file unexist.ent: %s\n", strerror(errno));return 0;
}

输出: 

也可以了解⼀下 perror 函数,perror函数相当于⼀次将上述代码中的第9⾏完成了,直接将错误信息 打印出来。perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL)perror("Error opening file unexist.ent");return 0;
}

输出: 


以上内容是我对于C语言字符函数和字符串函数的一些理解和分析,希望能对大家有所帮助。由于个人能力和知识有限,可能存在表述不准确或理解不深刻的地方,还请各位看客不吝指正。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SDN:逻辑上集中的控制平面,路由选择算法,LS路由工作过程,距离矢量路由选择(distance vector routing)】

文章目录 SDN&#xff1a;逻辑上集中的控制平面SDN的主要思路SDN控制平面和数据平面分离的优势SDN 架构: 数据平面交换机 路由选择算法路由(route)的概念最优化原则(optimality principle)路由的原则路由算法的分类LS路由工作过程&#xff08;相当于一个上帝&#xff09;链路状…

解决github无法克隆私有仓库,Repository not found问题(2024最新)

一、背景 这个问题出现&#xff0c;是你用了其他主机设备&#xff0c;需要重新clone私有库时&#xff0c;发现一直报找不到仓库&#xff0c;如下报错&#xff1a; remote: Repository not found.二、解决方法 &#xff08;1&#xff09;账号密码方式&#xff08;已不支持&am…

1069 微博转发抽奖

solution #include<iostream> #include<string> #include<map> using namespace std; int main(){int n, m, s, loop 0, have 0;string id;map<string, int> mp;cin >> m >> n >> s;for(int i 1; i < m; i){//编号从1开始cin…

HarmonyOS开发案例:【Stage模型下Ability的创建和使用】

介绍 基于Stage模型&#xff0c;对Ability的创建和使用进行讲解。首先在课程中我们将带领大家使用DevEco Studio创建一个Stage模型Ability&#xff0c;并使用UIAbilityContext启动另一个Ability&#xff0c;然后借助Want&#xff0c;在Ability之间传递参数&#xff0c;最后我们…

STC8增强型单片机开发

1.C51版本Keil环境搭建 下载地址是 Keil Product Downloads 选择C51进行下载&#xff1a; 2.STC环境添加 STC-ISP下载 进入stc官网 深圳国芯人工智能有限公司-工具软件 3.将STC添加到Keil中 打开stc-isp工具 按照图例点击按钮 选择keil的安装目录&#xff0c;以实际安装目…

6、随机森林(Random forests)

Random forests started a revolution in machine learning 20 years ago. For the first time, there was a fast and reliable algorithm which made almost no assumptions about the form of the data, and required almost no preprocessing. In today’s lesson, you’ll…

The Sandbox 案例|Web3 项目引领娱乐业的发展

Web3 如何通过 RZR 系列等项目开创娱乐新纪元。 我们已经看到技术和 Web3 如何颠覆金融和银行等行业&#xff0c;然而娱乐业在不断变化的环境中似乎发展滞后。传统的制片厂生态系统、高成本制作以及历史悠久的运作模式一直占据主导地位&#xff0c;而 Web3 项目的出现为创作者提…

Postgresql使用dblink实现跨库查询

一、背景介绍 回调表callback&#xff0c;在test数据库下&#xff0c;数据内容如下 公司表company&#xff0c;在release数据库下&#xff0c;数据内容如下 现在的需求是查询company公司下的callback回调数据 二、实现思路 正常的想法直接两张表关联查询即可&#xff0c;很…

机器学习:基于TF-IDF算法、决策树,使用NLTK库对亚马逊美食评论进行情绪分析

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

LeetCode算法题:9. 回文数(Java解法)

给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数 是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&#xff0c…

Linux(openEuler、CentOS8)企业内网samba服务器搭建(Windows与Linux文件共享方案)

本实验环境为openEuler系统<以server方式安装>&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验1. 安装samba2. 启动smb服务并设置开机启动3. 查看服务器监听状态4. 配置共享访问用户5. 创建共享文件夹6. 修改配置文件7. 配置防火墙8. 使用windows…

Mysql 基础 - 常见 子句

算数运算符 > < > < !/<> 逻辑运算符 3i in is null is not null 2l limit like 2o or 、order by 1a and ib between and 1n not and、or 、not、 in、 orderby、 limit、 like、 between...and、 is null 、is not null