文章目录
字符函数和字符串函数
字符函数
下面介绍的函数均包含在头文件 <ctype.h> 中
字符分类函数
字符分类函数帮你判断一个字符是否是某个类型
我们举几个常见的字符分类函数:
- 判断字符是否是小写字母
int islower(int c);
如果字符是小写字母,函数返回一个非零的整数;如果字符不是小写字母,返回0
例如:
#include <stdio.h>
#include <ctype.h>
int main()
{
char c[] = {'g','2','S','!','\0'};
int len = sizeof(c) / sizeof(c[0]);
for(int i = 0; i < len - 1; i++)
{
int ret = islower(c[i]);
if(ret)
{
printf("%c是小写字母\n",c[i]);
}
else
{
printf("%c不是小写字母\n",c[i]);
}
}
return 0;
}
//打印结果是:
g是小写字母
2不是小写字母
S不是小写字母
!不是小写字母
字符分类函数的返回逻辑都是这样,判断为是,返回非0整数;判断不是,返回0。
字符转换函数
C提供了2个字符转换函数:字母大小写转换
int tolower(int c);//转换为小写
int toupper(int c);//转换为大写
以tolower为例,当我们传入的参数不是大写的字母时,返回值是原字符,不会做出任何改变;如果参数是大写的字母,则会返回它的小写字母。
#include <stdio.h>
#include <ctype.h>
int main()
{
char a[] = "Hello FrIenDs";
char c = 0;
int i = 0;
while(a[i])
{
c = toupper(a[i]);
printf("%c",c);
i++;
}
return 0;
}
//打印结果是:
HELLO FRIENDS
字符串函数
需要包含头文件 <string.h>
strlen
计算字符串长度
size_t strlen(const char* str);
-
计算的是\0之前的字符的个数(不包含\0)。
-
参数str指向的字符串必须以\0结束。
-
返回类型是size_t类型,是无符号整数类型,因为一个字符串的长度不可能为负数。
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[10] = "abcdef";
size_t ret = strlen(arr);
printf("%d\n",ret);//打印结果是6
return 0;
}
模拟实现
//1.
size_t My_strlen(const char* str)
{
assert(str);
size_t count = 0;
while(*str != '\0')
{
count++;
str++;
}
return count;
}
//2.
size_t My_strlen(const char* str)
{
assert(str);
if(*str == '\0')
return 0;
else
{
return 1 + My_strlen(str++);
}
}
//3.
size_t My_strlen(const char* str)
{
assert(str);
char* tmp = str;
while(*str != '\0')
{
str++;
}
return str - tmp;
}
strcpy
拷贝字符串到指定地址
char* strcpy(char* destination, const char* source);
- 目标字符串指向的空间必须可以修改,且足够大
- 源字符串必须以\0结尾
- 拷贝时会将\0拷贝到目标空间
- 返回的是目标字符串的起始地址
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char src[] = "hello friends";
char des[20] = { 0 };
char* ret = strcpy(des, src);
printf("%s\n", ret);//打印hello friends
return 0;
}
模拟实现
char* My_strcpy(char* des, const char* src)
{
assert(des && src);
char* tmp = des;
while (*des++ = *src++)
{
;
}
return tmp;
}
strcat
在某个字符串后追加字符
char* strcat(char* destination, const char* source);
- 实现逻辑:strcat函数会寻找目标空间的\0,然后将源字符串追加到后面,注意从\0这个位置追加,覆盖目标空间的\0,最终也会将源字符串的\0拷贝过去。
- 源字符串需要\0结尾,指示追加结束
- 目标字符串需要\0结尾,指示追加开始的位置
- 目标空间需要足够大并且可以修改
- 返回目标字符串的地址
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[30] = "hello ";
char a2[] = "friends";
char* ret = strcat(a1, a2);
printf("%s\n", ret);//打印hello friends
return 0;
}
当然,字符串可以追加自己。
模拟实现
char* My_strcat(char* des, const char* src)
{
assert(des && src);
char* tmp = des;
while (*des)
{
des++;
}
while (*des++ = *src++)
{
;
}
return tmp;
}
strcmp
比较两个字符串的内容
int strcmp(const char* str1, const char* str2);
- 比较方法:strcmp函数会将两个字符串一个一个进行比较,比较的是字符的ASCII码值,当两个字符的ASCII码值相等时,继续向后比较,当不相等时,若str1当前字符大于str2当前字符,函数返回一个大于0的数,相反,返回一个小于0的数
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[] = "abcdef";
char a2[] = "abcdy";
int ret = strcmp(a1, a2);
if (ret > 0)
{
printf("a1 > a2\n");
}
else if (0 == ret)
{
printf("a1 = a2\n");
}
else
{
printf("a1 < a2\n");
}
printf("%d\n", ret);
return 0;
}
//最终打印值为:
a1 < a2
-1
strcmp函数比较的是内容,不是长度,在例子中a1长度比a2长,但是,y的 ASCII码值大于e的,所以a2更大。
模拟实现
int My_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
strncpy
拷贝指定数量的字符到目标空间
char* strncpy(char* destination, const char* source, size_t num);
- num就是要拷贝的字符的数量
- 拷贝后不会在后面放\0
- 拷贝的个数比源字符串字符数量多,会用\0补充缺失的字符,直到拷贝加补充的字符数量达到num
- 返回的是目标字符串地址
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[] = "hello friends";
char a2[20] = { 0 };
char* ret = strncpy(a2, a1, 5);
printf("%s\n", ret);//输出hello
return 0;
}
strncat
在字符串后追加指定数量的字符
char* strncat(char* destination, const char* source, size_t num);
- num就是要追加的字符的数量
- 追加后会自动放一个\0,但是如果想追加的个数比源字符串长,不会补\0,这里要区别strncpy函数
- 返回目标字符串地址
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[30] = "hello friends";
char a2[20] = "! how are you?";
char* ret = strncat(a1, a2, 5);
printf("%s\n", ret);//输出hello friends! how
return 0;
}
strncmp
比较指定数量字符的内容
int strncmp(const char* str1, const char* str2, size_t num);
- num就是要比较的字符的个数
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[30] = "abcdefw";
char a2[20] = "abcdeff";
int ret = strncmp(a1, a2, 5);
if (ret > 0)
{
printf("a1 > a2\n");
}
else if (ret < 0)
{
printf("a1 < a2\n");
}
else
printf("a1 = a2\n");
return 0;
}
//输出:a1 = a2
strstr
在一个字符串里寻找另一个字符串。
char* strstr(const char* str1, const char* str2);
- 在str1指向的字符串中寻找str2指向的字符串,如果找到了,返回第一次出现的位置;如果找不到返回NULL
- \0不在比较范围内,作为结束标志
例如:
#include <stdio.h>
#include <string.h>
int main()
{
char a1[30] = "abcde";
char a2[20] = "ddabcdeff";
char* ret = strstr(a2, a1);
printf("%s\n", ret);//打印abcdeff
return 0;
}
模拟实现
char* My_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
const char* cur = str1;
if (*str2 == '\0')//特殊情况:要寻找的是空字符串
return (char*)str1;
while (*cur)
{
s1 = cur;//s1记录每次开始比较的位置,每次寻找失败初始化
s2 = str2;//s2记录每次开始比较的位置,每次寻找失败初始化
while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0')//找到相等的字符后面才可能找到指定字符串,继续向后比较,同时保证不是\0这一结束标志
{
s1++;
s2++;
}
if (*s2 == '\0')//寻找成功的标志
return (char*)cur;
cur++;
}
return NULL;
}
strtok
通过分隔符(标志),将字符串分割
char* strtok(char* str, const char* delimiters);
- delimiters指向的字符串,就是我们指定的分隔符(标志)的集合。可以是多个字符,字符内容不变的情况下,顺序无关结果。
- strtok会在str指向的目标空间寻找指定的标志,找到后会将标志换成\0,然后返回标志位置之前的一段字符串的起始地址。
- 由于strtok函数会改变目标字符串,所以我们在使用时,会将要查询的字符串strcpy一份,传参时传入拷贝的字符串的起始地址,strtok函数就会修改拷贝产生的空间的内容。
- 值得注意的是,strtok会记录上一次标志的位置,当我再次调用strtok函数查询上一个目标空间时,第一个参数传NULL,strtok会寻找下一个标志。
- 当字符串中不再有标志,返回NULL
#include <stdio.h>
#include <string.h>
int main()
{
char a1[] = "310xxx2934@qq.com";
char sign[] = "@.";
char copy[20] = { 0 };
//拷贝
char* cop = strcpy(copy, a1);
//第一次调用
char* ret = strtok(copy, sign);
printf("%s\n", ret);
//之后调用
ret = strtok(NULL, sign);
printf("%s\n", ret);
ret = strtok(NULL, sign);
printf("%s\n", ret);
ret = strtok(NULL, sign);
printf("%s\n", ret);
return 0;
}
打印结果:
310xxx2934
qq
com
(null)
strerror
会返回错误码对应的错误信息的字符串的地址
char * strerror ( int errnum );
-
errnum是错误码
-
我们通常在使用strerror函数时,会传errno这个变量
errno这个变量是在C程序开始时自动创建的一个全局变量。当我们在调用库函数时出错,errno变量会记录这一错误的错误码,比如0、1、2、3、4等等,我们当然不明白这个错误码是什么意思,基于此,头文件 <errno.h> 中记录了错误码对应的错误信息。
前面提到错误码是从0开始的,我们不妨打印一下0~10对应的的错误信息
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
for (int i = 0; i < 11; i++)
{
printf("%d :%s\n", i, strerror(i));
}
return 0;
}
//这段代码的打印结果是:
0 :No error
1 :Operation not permitted
2 :No such file or directory
3 :No such process
4 :Interrupted function call
5 :Input/output error
6 :No such device or address
7 :Arg list too long
8 :Exec format error
9 :Bad file descriptor
10 :No child processes
我们再模拟一下调用函数出错的情况,并打印错误信息
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
int* pi = (int*)malloc(10000000000000000000);
if(pi = NULL)
{
printf("%s\n",strerror(errno));
}
free(pi);
pi = NULL;
return 0;
}
//malloc是一个库函数,当我们给malloc传入一个相当大的数字,malloc函数会返回NULL,我们将错误信息打印得到:
Not enough space
以上就是常见的字符函数和字符串函数了。