文章目录
- 前言
- 字符函数
- 字符串函数
- 1. [strlen](https://cplusplus.com/reference/cstring/strlen/)的使用和模拟实现
- 2. [strcpy](https://cplusplus.com/reference/cstring/strcpy/)的使用与模拟实现
- 3. [strcat](https://cplusplus.com/reference/cstring/strcat/)的使用与模拟实现
- 4. [strcmp](https://cplusplus.com/reference/cstring/strcmp/)的使用与模拟实现
- 5. [strncpy](https://cplusplus.com/reference/cstring/strncpy/)、[strncat](https://cplusplus.com/reference/cstring/strncat/)和[strncmp](https://cplusplus.com/reference/cstring/strncmp/)的使用
- 6.[strstr](https://cplusplus.com/reference/cstring/strstr/)的使用与模拟实现
- 7.[strtok](https://cplusplus.com/reference/cstring/strtok/)的使用
- 8.[strerror](https://cplusplus.com/reference/cstring/strerror/)的使用
- 结语
前言
我们在编程学习的过程中,是一定要处理字符和字符串的,为了方便操作字符和字符串,C语言标准库提供了一系列的库函数,接下来就让我们学习这些函数吧。
字符函数
字符分类函数
C语言中有一系列的函数是专门用来做字符分类的,也是将一个字符判断是属于什么类型的字符。
这些函数的使用都需要包含一个头文件<ctype.h>
(c -> 字符,type -> 类型,ctype -> 字符类型)
函数 | 如果函数的参数符合以下条件返回真(非0) |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格’ ‘,换页’\f’,换行’\n’,回车’\r’,制表符’\t’或者垂直制表符’\v’ |
isdigit | 十进制数字 0 ~ 9 |
isxdigit | 十六进制数字:0 ~ 9、小写字母a ~ f( or 大写字母 A ~ F) |
islower | 小写字母 a ~ z |
isupper | 大写字母 A ~ Z |
isalpha | 字母 a ~ z 或 A ~ Z |
isalnum | 字母或数字: a ~ z,A ~ Z,0 ~ 9 |
ispunct | 标点符号:不属于数字与符号的可打印的图形字符 |
isgraph | 任何图形字符 |
isprint | 如何可打印字符,包括图形字符和空白字符 |
这些函数的使用方法都大同小异,就拿一个函数来使用。
int isupper ( int c );
isupper是判断参数的C是否为大写字母的
如果是大写字母就返回非0;相反则返回0.
函数使用
情景:写一个代码,将字符串中的大写字母转小写,其他字符不变
//写⼀个代码,将字符串中的大写字⺟转小写,其他字符不变。
int main()
{
char str[] = "heLLo WorLd.,\n";
char c = 0;
int sz = sizeof(str) / sizeof(str[0]) - 1;//因为sizeof在计算字符串时,会把\0也计算进去,但是这个\0的长度我们并不需要
//size_t sz = strlen(str) 当然,你也可以用库函数strlen
for (int i = 0; i < sz; i++)
{
c = str[i];
if (isupper(c))
{
c += 32;//大写字母与小写字母的ASCII码值相差32
}
putchar(c);//输出一个字符
}
return 0;
}
字符转换函数
C语言提供了2个字符转换函数:
函数 | 功能 |
---|---|
tolower | 将大写字母转为小写字母 |
toupper | 将小写字母转为大写字母 |
int tolower ( int c );
int toupper ( int c );
上面的代码,我们小写转大写是通过操作ASCII码值实现的,我们现在学习了这两个库函数,就可以直接用tolower
函数
int main()
{
char str[] = "heLLo WorLd.,\n";
char c = 0;
int sz = sizeof(str) / sizeof(str[0]) - 1;//因为sizeof在计算字符串时,会把\0也计算进去,但是这个\0的长度我们并不需要
//size_t sz = strlen(str) 当然,你也可以用库函数strlen
for (int i = 0; i < sz; i++)
{
c = str[i];
if (isupper(c))
{
c = tolower(c);
}
putchar(c);//输出一个字符
}
return 0;
}
字符串函数
接下来讲解的字符串函数的头文件都是 <string.h>
1. strlen的使用和模拟实现
size_t strlen( const char *string );
字符串以'\0'
作为结束标记,strlen计算并返回的是字符串中'\0'
之前的字符个数(其中并不包含'\0'
)
注意事项
1.函数参数所指向的字符串必须要有'\0'
(不然就会是随机值)
2.函数的返回值的类型是size_t
,是无符号的
3.使用前需要包含头文件
#include<stdio.h>
#include<string.h>
int main()
{
const str[] = "abcdefg";//7
size_t ret = strlen(str);
printf("%zd\n", ret);
return 0;
}
模拟实现
方法一(计数器方式)
#include<assert.h>
//模拟实现1(创建临时变量)
int my_strlen1(const char* str)
{
assert(str);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
方法二(不创建临时变量)
#include<assert.h>
//2(递归)
int my_strlen2(const char* str)
{
assert(str);
if (*str == '\0')
{
return 0;
}
return 1 + my_strlen2(str + 1);
}
方法三(指针 - 指针)
#include<assert.h>
//3(指针-指针)
int my_strlen3(const char* str)
{
assert(str);
char* tmp = str;
while (*str)
{
str++;
}
return str - tmp;
}
2. strcpy的使用与模拟实现
char * strcpy ( char * destination, const char * source );
CopiestheCstringpointedbysourceintothearraypointedbydestination, including the terminating null character (and stopping at that point).
将指向的源头字符串复制到指向目的地的数组中,包括结束符空字符'\0
’(并在该点停止)。
注意事项
1.源头字符串必须要有'\0'
2.strcpy会把源头字符串的'\0'
拷贝到目标空间
3.目标空间必须足够大,确保能存放源字符串
4.目标空间不能用const
修饰
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "Guang Dong";
char str2[20] = { "XXXXXXXXXXXXXXXXXXX" };
printf("使用前: %s\n", str2);
strcpy(str2, str1);
printf("使用后: %s\n", str2);
return 0;
}
模拟实现
#include<assert.h>
#include<string.h>
//strcpy的使用与模拟
//字符串拷贝(会拷贝源头的'\0')
char* my_strcpy(char* dis, const char* src)
{
assert(dis && src);
char* tmp = dis;
//第一版
//while (*src != '\0')
//{
// *dis = *src;
// dis++;
// src++;
//}
//*dis = *src;
//第二版(优化)
//while (*dis = *src)
//{
// dis++;
// src++;
//}
//第三版(再优化)
while (*dis++ = *src++)
;
return tmp;
}
运行结果
3. 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 ofthe new string for medby the concatenation of both in destination.
将复印一个源字符串附加到目标字符串。目标字符串中的终止空字符('\0')
会被源字符串的第一个字符覆盖,新字符串的末尾也会包含一个空字符,以便对目标字符串中的两个字符串的连接进行调解。
注意事项
1.源字符串必须要有'\0'
2.目标字符串也要有'\0'
,否则没办法知道从哪里开始追加字符串
3.目标空间要足够大,能容纳下新增的内容
4.目标空间斌不能被const
修饰
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "GuangDong";
char str2[30] = { "Welcome to the " };
printf("增加前 %s\n", str2);
strcat(str2, str1);
printf("增加后 %s\n", str2);
return 0;
}
模拟实现
//strcat的使用与模拟
//在目标字符串的'\0'处拷贝源字符串(拷贝'\0')
char* my_strcat(char* dis, const char* src)
{
assert(dis && src);
char* tmp = dis;
while (*dis != '\0')
{
dis++;
}
while (*dis++ = *src++)
;
return tmp;
}
int main()
{
char str1[] = "GuangDong";
char str2[30] = { "Welcome to the " };
printf("增加前 %s\n", str2);
my_strcat(str2, str1);
printf("增加后 %s\n", str2);
return 0;
}
4. 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.
该函数从每个字符串的第一个字符开始比较。如果彼此相等,则继续比较下面的字符对,直到字符不同或出现终止的空字符为止。(比较的是字符之间的ASCII码值,与字符串的长度没关系)
规定
第一个字符串的字符大于第二个字符串的字符,返回大于0的数字
第一个字符串的字符等于第二个字符串的字符,返回0
第一个字符串的字符小于第二个字符串的字符,返回小于0的数字
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abcde";
char str2[] = "abd";
int ret = strcmp(str1, str2);
if (ret > 0)
{
printf("str1 大于 str2");
}
else if (ret == 0)
{
printf("str1 等于 str2");
}
else
printf("str1 小于 str2");
return 0;
}
模拟实现
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')//两个都走到了\0
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
上面最后一行的代码很巧妙的比较了字符之间大小,并且也返回了值
5. strncpy、strncat和strncmp的使用
1.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
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 个字符之前发现源 C 字符串的结束标志'\0'
,则将用 0 填充目标字符串,直到总共写入 num 个字符为止。
从源字符串拷贝 num 个字符到目标空间
如果源字符串的长度小于 num,则在拷贝完源字符串后,会在目标空间后面追加 0 ,直到 num个
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "GuangDongSheng";//长度为字符串长度+\0
const char str2[] = "QingYuan";
printf("使用函数前:%s\n", str1);
strncpy(str1, str2, 10);
printf("使用函数后:%s\n", str1);
return 0;
}
2.strncat
char * strncat ( char * destination, const char * source, size_t num );
Appends the first num characters of source to destination, plus a terminating null-character.(将源字符串的前 num 个字符加一个空字符作为结束符,追加到目的地。)
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果源字符串的长度小于 num,则只会将字符串中到 '\0'
的内容追加到目标空间末尾)
#include<stdio.h>
#include<string.h>
int main()
{
char str1[50] = "GuangDongSheng";
const char str2[] = "QingYuanShi";
printf("使用函数前:%s\n", str1);
strncat(str1, str2, 15);
printf("使用函数后:%s\n", str1);
return 0;
}
3.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
其实和前两个函数是差不多的,只不过该函数比较的是 str1 与 str2 的前 num 个字符,如果相等就往后比较,那么最多能比较 num 个字符,如果提前发现不一样,就会提前结束
#include<stdio.h>
#include<string.h>
int main()
{
const char str1[] = "abcde";
const char str2[] = "abcdd";
printf("%d",strncmp(str1, str2,4));
return 0;
}
6.strstr的使用与模拟实现
const char * strstr ( const char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(返回str2字符串第一次出现在str1字符串的位置)
The matching process does not include the terminating null-characters, but it stops there.(字符串的比较匹配并不包含字符'\0'
,而是以字符'\0'
作为结束标志)
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abbbbbcaa";
char str2[] = "bbc";
char* ret = strstr(str1, str2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
模拟实现
思路:
1.需要记录开始比配时的地址(如果匹配失败了,会返回到开始匹配时的地址)
2.匹配失败往前指针往前走一步
3.如果str1走到了'\0'
,返回NULL
特殊情况:
如果str2是一个空字符串const char str2 = "\0"
,那么返回的时str1的起始地址
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == '\0')//特殊情况
{
return (char*)str1;
}
char* tmp = str1;
while (*tmp)
{
const char* s1 = tmp;//用来记录str1的地址,用于匹配
const char* s2 = str2;//用来记录str2的地址,用于匹配
while (*s1 == *s2)//开始匹配
{
s1++;
s2++;
}
if (*s2 == '\0')
return tmp;
tmp++;
}
return NULL;
}
7.strtok的使用
char * strtok ( char * str, const char * delimiters )
1.delimiters参数指向一个字符串,将指向的字符串定义为分隔符
2.str指向一个字符串,它包含了0个或多个由delimiters字符串中的一个或多个分割字符
3.strtok函数会直到str中的分割字符,并将其换成'\0'
,返回被分割的字符串的首元素地址
4.strtok函数的str不为NULL
,函数将找到str中第一个分割字符,并会保留它在str字符串中的位置(下次进来就是在分割字符的地址处)
5.strtok函数的str为NULL
,函数将在被保留的位置开始,查找下一个分割字符
6.如果strtok找不到更多的str中的分割字符,则会返回NULL
指针。
#include<stdio.h>
#include<string.h>
int main()
{
char str[] = "192.268.354.456@163.com";
char sep[] = ".@";
char* tmp = NULL;
for (tmp = strtok(str, sep); tmp != NULL; tmp = strtok(NULL, sep))
{
printf("%s ", tmp);
}
return 0;
}
8.strerror的使用
char * strerror ( int errnum );
解释 errnum 的值,生成一个带有信息的字符串,描述错误原因。
在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在<errno.h>
头文件中,在我们启动C语言程序的时候就会使用一个全局变量errno来记录程序当前的错误码,这不过在启动时errno是0(没有错误),当我们的程序发生了某个错误,就会将对应的错误码存放在errno中,但是很难理解错误码的意思,所以每个错误码都会有一个对应的错误信息,strerror函数就可以返回对应的错误信息字符串的地址。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++)//C语言有很多个错误码,这里取11个来展示
{
printf("%s\n", strerror(i));
}
return 0;
}
错误信息 | 翻译 |
---|---|
No error | 没有错误 |
Operation not permitted | 不允许操作 |
No such file or directory | 找不到文件或目录 |
No such proces | 没有这样的程序 |
Interrupted function call | 函数调用中断 |
Input/output error | 输入 / 输出错误 |
No such device or address | 没有这样的设备或地址 |
Arg list too long | 列表参数过长 |
Exec format error | 执行格式错误 |
Bad file descriptor | 无效的文件 |
No child processes | 没有子过程 |
结语
感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言。如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!