[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函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。
完。