当前位置: 首页 > news >正文

[C]基础14.字符函数和字符串函数

  • 博客主页:向不悔
  • 本篇专栏:[C]
  • 您的支持,是我的创作动力。

文章目录

  • 0、总结
  • 1、字符分类、转换函数
  • 2、strlen的使用和模拟实现
    • 2.1 strlen的使用
    • 2.2 strlen的模拟实现
  • 3、strcpy的使用和模拟实现
    • 3.1 strcpy的使用
    • 3.2 strcpy的模拟实现
  • 4、strcat的使用和模拟实现
    • 4.1 strcat的使用
    • 4.2 strcat的模拟实现
  • 5、strcmp的使用和模拟实现
    • 5.1 strcmp的使用
    • 5.2 strcmp的模拟实现
  • 6、strncpy函数的使用
  • 7、strncat函数的使用
  • 8、strncmp函数的使用
  • 9、strstr的使用和模拟实现
    • 9.1 strstr的使用
    • 9.2 strstr的模拟实现
  • 10、strtok函数的使用
  • 11、strerror函数的使用


0、总结

在这里插入图片描述

在编程的过程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,我们要学习一下这些函数。

1、字符分类、转换函数

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

常用的分类函数如下:

  • isspace:空白字符,https://cplusplus.com/reference/cctype/isspace/
  • isdigit:十进制数字,https://cplusplus.com/reference/cctype/isdigit/
  • islower:小写字母a~z,https://cplusplus.com/reference/cctype/islower/
  • isupper:大写字母A~Z,https://cplusplus.com/reference/cctype/isupper/

转换函数的头文件也是ctype.h,参考如下:

  • tolower:大写转小写,https://cplusplus.com/reference/cctype/tolower/
  • toupper:小写转大写,https://cplusplus.com/reference/cctype/toupper/

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

#include <stdio.h> /* printf */
#include <ctype.h> /* islower、toupper */
#include <string.h> /* strlen */int main()
{char str[] = "hello,world";int len = strlen(str);int i = 0;for (i = 0; i < len; i++){if (islower(str[i])) str[i] = toupper(str[i]);}printf("%s\n", str);return 0;
}

2、strlen的使用和模拟实现

2.1 strlen的使用

介绍:

  • 头文件:string.h
  • 函数原型:size_t strlen(const char* str);
  • 作用:计算字符串的长度
  • 参考:https://cplusplus.com/reference/cstring/strlen/

总结如下:

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

2.2 strlen的模拟实现

方式一:计数器方式

#include <stdio.h> /* printf */
#include <assert.h>int my_strlen(const char* str)
{int count = 0;// 如果str是空指针,程序会输出一条错误的信息并终止执行。// 因为如果直接对空指针进行解引用,会导致程序崩溃。assert(str);// 循环一直执行,直到str指向的字符是空字符\0。while (*str){count++;str++;}return count;
}int main()
{const char* str = "abc";int len = my_strlen(str);printf("%d\n", len);return 0;
}

方式二:不能创建临时变量计数器

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

方式三:指针-指针的方式

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

3、strcpy的使用和模拟实现

3.1 strcpy的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strcpy(char* destination, const char* source);
  • 作用:拷贝字符串到目标空间
  • 参考:https://cplusplus.com/reference/cstring/strcpy/

总结如下:

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

3.2 strcpy的模拟实现

题目出自《高质量C/C++编程》书籍最后的试题部分

#include <stdio.h> /* printf */
#include <assert.h>char* my_strcpy(char* dest, const char* src)
{char* ret = dest;assert(dest);assert(src);// 赋值后的结果(即*src的值作为条件)// 当*src为'\0'时候,条件为假,循环结束。// 就是说,先获取*src的值,再将这个值赋给*dest,用这个值(即*src的值)作为循环的条件。while (*dest++ = *src++);return ret;
}int main()
{char a[30] = "xxxxxxxx";char b[4] = "abc";printf("复制前:%s\n", a);my_strcpy(a, b);printf("复制后:%s\n", a);return 0;
}

解释while (*dest++ = *src++);,如下:

4、strcat的使用和模拟实现

4.1 strcat的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strcat(char* destination, const char* source);
  • 作用:追加目标字符串
  • 参考:https://cplusplus.com/reference/cstring/strcat/

总结如下:

  • 源字符串必须以’\0’结束。
  • 目标字符串中也得有’\0’,否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,且必须可修改。
  • 字符串自己给自己追加,如何?

4.2 strcat的模拟实现

#include <stdio.h> /* printf */
#include <assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest);assert(src);while (*dest) dest++;while (*dest++ = *src++);return ret;
}int main()
{char a[30] = "xxxxxxxx";char b[4] = "abc";printf("复制前:%s\n", a);my_strcat(a, b);printf("复制后:%s\n", a);return 0;
}

my_strcat函数在将字符串自己追加自己时会导致无限循环,可能引发程序崩溃。

5、strcmp的使用和模拟实现

5.1 strcmp的使用

介绍:

  • 头文件:string.h
  • 函数原型:int strcmp(const char* str1, const char* str2);
  • 作用:比较字符串的大小
  • 参考:https://cplusplus.com/reference/cstring/strcmp/

总结如下:

  • 第一个字符串大于第二个字符串,则返回大于0的数字。
  • 第一个字符串等于第二个字符串,则返回0。
  • 第一个字符串小于第二个字符串,则返回小于0的数字。
  • 是如何判断两个字符串呢?比较两个字符串中对应位置上字符ASCII码值的大小。

5.2 strcmp的模拟实现

#include <stdio.h> /* printf */
#include <assert.h>int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){// if (*str1 == '\0') 和 if (*str2 == '\0') 在逻辑上是等价的,// 因为当两个字符串相等时,它们会同时到达末尾(即遇到'\0')。if (*str1 == '\0')return 0;str1++;str2++;}return *str1 - *str2;
}int main()
{char arr1[] = "abq";char arr2[] = "abcdef";int ret = my_strcmp(arr1, arr2);printf("%d\n", ret);return 0;
}

6、strncpy函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strncpy(char* destination, const char* source, size_t num);
  • 作用:拷贝num个字符从源字符串到目标空间
  • 参考:https://cplusplus.com/reference/cstring/strncpy/

注意:如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

7、strncat函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strncat(char* destination, const char* source, size_t num);
  • 作用:将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加一个\0字符。
  • 参考:https://cplusplus.com/reference/cstring/strncat/

注意:如果source指向的字符串的长度小于num的时候,只会将字符串中到\0的内容追加到destination指向的字符串末尾。

8、strncmp函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:int strncmp(const char* str1, const char* str2, size_t num);
  • 作用:比较str1和str2的前num个字符
  • 参考:https://cplusplus.com/reference/cstring/strncmp/

9、strstr的使用和模拟实现

9.1 strstr的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strstr(const char*, const char*);
  • 作用:函数返回字符串str2在字符串str1中第一次出现的位置。
  • 参考:https://cplusplus.com/reference/cstring/strstr/

注意:字符串的比较匹配不包含\0字符,以\0作为结束标志。

9.2 strstr的模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>char* my_strstr(const char* str1, const char* str2)
{char* cp = (char*)str1;char* s1, * s2;if (!*str2)return (char*)str1;while (*cp){s1 = cp;s2 = (char*)str2;while (*s1 && *s2 && !(*s1 - *s2))s1++, s2++;if (!*s2)return cp;cp++;}return NULL;
}int main()
{char s1[] = "aaabbbcccdefbbcdefa";char s2[] = "ccdef";printf("%s\n", my_strstr(s1, s2));return 0;
}

10、strtok函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strtok(char* str, const char* delimiters);
  • 作用:分割字符串
  • 参考:https://cplusplus.com/reference/cstring/strtok/

总结如下:

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

示例:

#define _CRT_SECURE_NO_WARNINGS 1
#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;
}
运行:
192
168
6
111

11、strerror函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strerror(int errnum);
  • 作用:将错误码转换为对应的错误信息字符串地址。
  • 参考:https://cplusplus.com/reference/cstring/strerror/

总结如下:

函数能返回对应错误码的错误信息字符串地址。系统和 C 语言标准库规定了一些错误码,一般在头文件中说明。程序启动时用变量记录当前错误码,初始为 0 表示无错误。调用标准库函数出错时,会将对应错误码存入因错误码是整数较难理解,所以每个错误码都有对应的错误信息,函数就能返回该错误信息字符串的地址。

打印0~10这些错误码对应的信息

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>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

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>int main()
{FILE* pFile;pFile = fopen("1.txt", "r");if (pFile == NULL)printf("Error:%s\n", strerror(errno));return 0;
}
运行:
Error:No such file or directory

也可以了解perror函数,总结如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>int main()
{FILE* pFile;pFile = fopen("1.txt", "r");if (pFile == NULL)perror("Error 1.txt");return 0;
}
运行:
Error 1.txt: No such file or directory

所以,perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。


完。

http://www.xdnf.cn/news/211789.html

相关文章:

  • 网络原理—应用层和数据链路层
  • 指针(5)
  • Spring Boot 集成 ActiveMQ 实现异步消息通信(一)
  • 跨平台项目部署全攻略:Windows后端+Mac前端在服务器的协同实战
  • Arduion 第一天,变量的详细解析
  • 三格电子——四路CAN转4G网关使用中的常见问题
  • 【深度学习新浪潮】ISP芯片算法技术简介及关键技术分析
  • 深度解析 MyBatis`@TableField(typeHandler = JacksonTypeHandler.class)`:优雅处理复杂数据存储
  • 深入理解二分查找
  • AI防摔倒检测系统
  • 实验七:基于89C51和DS18B20的温度采集与显示
  • 【从滚动条缺失到布局体系:前端布局问题的系统性思考】
  • pytorch 一些常用语法
  • 图漾官网Sample_V1版本C++语言完整参考例子---单相机版本
  • 企业办公协同平台安全一体化生态入住技术架构与接口标准分析报告
  • ubnuntu使用conda进行虚拟环境迁移,复制,克隆
  • Dify 使用模版转换实现更丰富的输入格式支持
  • linux FTP服务器搭建
  • 通信协议——SPI通信协议
  • Go语言中的错误处理
  • CSS:编写位置分类
  • PDF编辑器:Foxit PDF Editor Pro 版功能解析
  • JVM对象存储格式
  • 解决调用Claude 3.7接口 403 Request not allowed问题
  • 贝叶斯优化RF预测模型
  • 轻松实现CI/CD: 用Go编写的命令行工具简化Jenkins构建
  • 处理pdf文件的常用库unstructured和PyPDF2
  • 【PyTorch动态计算图原理精讲】从入门到灵活应用
  • vscode 配置qt
  • WEB漏洞--CSRF及SSRF案例