这篇博客为你归纳了所有的字符函数和最常用的字符串函数,以及对应的模拟实现!!你可以直接循着目录跳到你需要的段落哦!!😍
目录
字符函数
字符分类
字符判断函数
islower——判断小写字母
isupper——判断大写字母
isalpha——判断英文字母
isspace——判断空白字符
isblank——判断空格字符
isdigit——判断十进制数字
isxdigit——判断十六进制数字
isalnum——判断字母和数字
ispunct——判断标点圆形符号
isgraph——判断圆形字符
isprint——判断可打印的字符
iscntrl——判断控制字符
字符转换函数
toupper——小写字母转大写
tolower——大写字母转小写
字符串函数
strlen——计算字符串长度
strcpy——复制字符串
strcat——连接字符串
strcmp——字符串比较
strncpy、strncat、strncmp——限制长度的比较、连接和复制
strtok——主字符串中提取字符串
strsrt——模式串匹配
strerror——返回错误信息字符串。
memcpy——内存复制
memmove——内存挪移
memset——设置内存
memcmp——以字节为单位比较数据
结语:
字符函数
字符函数分为两类:字符判断和字符转换。它们都包含在头文件<ctype.h>中。字符函数都只有一个参数,int c。参数为int,是因为函数要把你传入的字符强制类型转换为整数ASCII码值,通过比较ASCII码来判断字符。
如:
字符分类
C语言使用ASCII美国信息交换标准代码,ASCII码值一共256个字符。其中,0~127为C标准规定的,最常用的字符ACSII码值。128~256为扩展字符集,而是否支持扩展字符集,取决于平台和编译环境。
下表中,被“X”号标记的,表示对应字符会被该字符函数判断为真。
原表格可打开此链接查看:<cctype> (ctype.h) - C++ Reference (cplusplus.com)(在此网页最下方)
分类简图:
字符判断函数
字符判断函数,用来判断传入的字符是否为期望的字符。
i.字符判断函数的参数范围:
参数值的范围为0~255;
如果传入了一个数值大于char类型大小范围的整数,程序就会报错!
下面的代码尝试打印出字符函数isspace的返回值,但是报错了,因为a的值超过了0~255的范围。
ii.字符判断函数的返回结果:
若是,则返回一个真值(随机非0值);
若不是则返回假值(0)。
islower——判断小写字母
功能:判断是否为小写字母,‘ a ’ ~ ‘ z ’。
示例:
char data1 = 'a';
char data2 = '1';
if(islower(data1))
{printf("good!\n");
}
else
{printf("no!no!no!");
}
if(islower(data2))
{printf("good!\n");
}
else
{printf("no!no!no!");
}
//输出结果为:
//good!
//no!no!no!
运行结果:
isupper——判断大写字母
功能:判断是否为大写字母,‘ A ’ ~ ‘ Z ’。
示例:
char data1 = 'A';
char data2 = 'a';
if(islower(data1))
{printf("good!\n");
}
else
{printf("no!no!no!\n");
}
if(islower(data2))
{printf("good!\n");
}
else
{printf("no!no!no!\n");
}
//输出结果为:
//good!
//no!no!no!
运行结果:
isalpha——判断英文字母
功能:判断是否为英文字母,‘ A ’ ~ ‘ Z ’,‘ a ’ ~ ‘ z ’。
示例:
int main()
{char str[20] = {"12abjkAB7890"};for (int i = 0; i < 12; i++){if (isalpha(str[i])){printf("第%d个字符是英文字母符\n", i + 1);}else{printf("不是英文字母符\n");}}return 0;
}
运行结果:
isspace——判断空白字符
功能:判断是否为空白符。
空白符为:" "(空格)、" \f "(换页)、" \n "(换行)、" \r "(回车)、" \t "(制表符)、" \v "(垂直制表符)。
示例:
int main()
{char str[10] = { '\n','\t','\v','\r',' ','\f','g' };for (int i = 0; i < 7; i++){if (isspace(str[i])){printf("第%d个字符是空白符\n", i + 1);}else{printf("不是空白符\n");}}return 0;
}
运行结果:
isblank——判断空格字符
功能:判断是否为空格字符,‘ ’、‘ \t ',为空格字符,' \t '也是空格字符喔,可以理解为' \t '是若干个 ' '(空格)。
示例:
int main()
{char str[] = {"11 22 \t"};int count = 0;for (int i = 0; i < 9; i++){if (isblank(str[i])){count++;}else{printf("第%d个字符%c不是空格字符\n", i + 1, str[i]);}}printf("一共有%d个空格字符\n",count);return 0;
}
运行结果:
isdigit——判断十进制数字
功能:判断是否为十进制数字符号, ’ 0 ‘ ~ ’ 9 ‘。
示例:
int main()
{char str[20] = {"1234jk567890"};for (int i = 0; i < 12; i++){if (isdigit(str[i])){printf("第%d个是字符是十进制数字符\n", i + 1);}else{printf("不是数字符\n");}}return 0;
}
运行结果:
isxdigit——判断十六进制数字
功能:判断十六进制数字字符,‘ 0 ’ ~ ‘ 9 ’ 、‘ a ’ ~ ‘ f ’、‘ A ’ ~ ‘ F ’。
示例:
int main()
{char str[20] = {"12abjKAB7890"};for (int i = 0; i < 12; i++){if (isxdigit(str[i])){printf("第%d个数字是十六进制数字符\n", i + 1);}else{printf("不是数字符\n");}}return 0;
}
运行结果:
isalnum——判断字母和数字
功能:判断是否为英文字母或者数字,‘ 0 ’ ~ ‘ 9 ’ 、‘ a ’ ~ ‘ z ’、‘ A ’ ~ ‘ Z ’
示例:
int main()
{char str[20] = {"12abjKAB7890_\n"};for (int i = 0; i < 12; i++){if (isalpha(str[i])){printf("第%d个字符是英文字母符或者数字符\n", i + 1);}else{printf("啥也不是\n");}}return 0;
}
运行结果:
ispunct——判断标点圆形符号
功能:判断是否为标点圆形符号,~ ! @ # $ % ^ & * ( ) _ + = - ` [ ] \ { } | ; ' : " , . / < > ?。
即键盘上除了数字、字母、控制符和空白符之外,所有的英文圆形标点符号。
示例:
int main()
{char str[] = {"https://blog.csdn.net/Elnaij?spm=1000.2115.3001.5343"};int count = 0;for (int i = 0; i < 53; i++){if (ispunct(str[i])){count++;}}printf("一共有%d个标点圆形符号\n",count);return 0;
}
运行结果:
isgraph——判断圆形字符
功能:判断是否为圆形字符。除了空白符和控制字符外,其余符号都为圆形字符。
示例:
int main()
{char str[] = {"https://blog.csdn.net/Elnaij?spm=1000.2115.3001.5343 <-very good!"};int count = 0;for (int i = 0; i < 66; i++){if (isgraph(str[i])){count++;}else{printf("第%d个字符%c不是圆形字符\n", i + 1, str[i]);}}printf("一共有%d个圆形字符\n",count);return 0;
}
运行结果:
isprint——判断可打印的字符
功能:判断是否为可打印字符。所有的字母、数字、空格(其他空白符可不算喔)、英文圆形标点符号都是可打印字符。
示例:
int main()
{char str[] = { "https://blog.csdn.net/Elnaij?spm=1000.2115.3001.5343\t\a\0\n" };int count = 0;for (int i = 0; i < 56; i++){if (isprint(str[i])){count++;}else{printf("第%d个字符%c不是可打印字符\n", i + 1, str[i]);}}printf("一共有%d个可打印字符\n", count);return 0;
}
运行结果:
虽然' \n '和 ' \t '不归类于可打印字符,但作为空白符的效果还是可以输出。
iscntrl——判断控制字符
功能:判断是否为控制字符。ASCII码值为0~31以及127的字符都为控制字符,其中包括了除去空格外的其他空白符。
这些空白符都叫做空白格控制字符(White-space Control Code)。
‘ \t ’不属于控制字符,但是属于空白符。
示例:
int main()
{char str[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,48,49,50,77,88,99 };
//赋ASCII码值int count = 0;for (int i = 0; i < 39; i++){if (iscntrl(str[i])){count++;}else{printf("第%d个字符%c不是控制字符\n", i + 1, str[i]);}}printf("一共有%d个控制符号\n",count);return 0;
}
运行结果:
字符转换函数
字符转换函数不像字符判断函数,就算传入的参数不合法也不会报错。对于转换不了的参数,他会放弃转换,返回传入参数的原值。
toupper——小写字母转大写
功能:将小写字母转换为大写,并返回转换结果。如果传入的不是小写字母,就返回传入的字符。
示例:
int main()
{int a = 300;printf("传入的值为%d\n", a);printf("转换结果为:%d\n",toupper(a));char c = 'f';printf("传入的值为%c\n", c);printf("转换结果为:%c\n", toupper(c));return 0;
}
运行结果:
tolower——大写字母转小写
功能:将大写字母转为小写,并返回转换结果。如果传入的不是小写字母,就返回传入的字符。
示例:
int main()
{int a = 300;printf("传入的值为:%d\n", a);printf("转换结果为:%d\n",tolower(a));char c = 'F';printf("传入的值为:%c\n", c);printf("转换结果为:%c\n", tolower(c));return 0;
}
运行结果:
字符串函数
字符串函数,可按照功能分为这5类:复制函数、连接函数、对比函数、查找函数和其他类型
字符串函数都包含在头文件<string.h>中,都能对字符串进行操作。
以下函数按照使用的频率的顺序来介绍,就不按分类来介绍了。
strlen——计算字符串长度
定义:size_t strlen ( const char * str );
功能:传入一个字符串,计算该字符串长度。该函数以字符串的第一个‘ \0 '之前的元素个数是作为字符串长度返回,因此,它会一直计数,直到遇到' \0 '才会停止计数。
!!注意!!
若字符串内没有' \0 ',他会继续越界访问字符串之外的内存来找' \0 ',且程序是不会报错。已知,未开辟空间内的数据为随机值,所以出现0值(即‘ \0 ’)也是随机的,导致它返回的长度也会是个随机值。这种属于危险操作,使得程序不可控。
(对于这种错误,VS编译器会报警告。)
示例:
int main()
{char str[] = "I am a handsome guy";char arr[5] = { 'a','b','c','d','e' };printf("字符串str的长度为:%zd\n字符串arr的长度为:%zd", strlen(str), strlen(arr));return 0;
}
运行结果(及错误示例——arr没有' \0 '):
strcpy——复制字符串
定义:char * strcpy ( char * destination, const char * source );
功能:将source源字符串拷贝到destination目标串中,从源字符串头开始复制,从目标字符串头开始拷贝。(' \0 '也会拷贝进去喔!)
!!注意!!
①源字符串内必须要有 ’ \0 '。因为该函数复制停止的条件是遇到’ \0 ',如果没有,就会越界,一直复制直到找到0值(即 ' \0 ')。这属于危险操作,会使得程序不可控,同上strlen函数。
②目标字符串要有足够的空间接受源字符串的复制,多出来的字符仍然会越界赋值。同样是危险的操作。
示例:
int main()
{char str[] = "I am a handsome guy";char arr[] ="abcedf";printf("源字符串为:%s\n目标字符串为:%s\n", arr, str);strcpy(str, arr);printf("拷贝结果为:%s\n", str);return 0;
}
运行结果:
错误示例1(arr没有' \0 '):
错误示例2(目标字符串空间不足,这种情况会引发异常,直接报错,程序停止运行):
strcat——连接字符串
定义:char * strcat ( char * destination, const char * source );
功能:将源字符串source连接到目标字符串末尾,连接时会覆盖掉目标字符串destination末尾的 ' \0 '。(实际上是将源字符串拷贝到目标字符串的末尾,就像两个字符串连接起来一样)
!!注意!!
①传入的两个字符串都要有' \0 ',一个让函数找到目标字符串的末尾,即连接位置;另一个让函数找到源字符串的末尾,即停止拷贝处。
②同样的,目标空间要足够大,不然会越界。
③不可以自己连接自己,不然拷贝的时候会把原来的' \0 '覆盖掉,函数找不到' \0 ',拷贝就停不下来了。
原本是这样:
连接一个字符过去变成这样:
此时字符串里已经没有了' \0 ',造成了源字符串和目标字符串都没有' \0 '的局面,程序无法停止,最终导致越界(vs会让这样的死循环停止,但是还是会产生奇怪的结果,所以还是不要这么做了)。
示例:
int main()
{char str[30] = "I am a ";char arr[] = "handsome guy";printf("源字符串为:%s\n目标字符串为:%s\n", arr, str);strcat(str, arr);printf("连接结果为:%s\n", str);return 0;
}
运行结果:
错误示例1(源字符串或者目标字符串没有' \0 ',在找字符串的末尾时导致越界)
错误示例2(str空间不足,虽然多出来的字符串是复制过去了,但是是复制在了未开辟的空间里,导致%s打印时,str数组没有' \0 '只能越界访问,最终程序崩溃):
错误示例3(自己连接自己,函数找不到 ' \0 ',导致越界访问):
strcmp——字符串比较
定义:int strcmp ( const char * str1, const char * str2 );
功能:比较两个字符串是否相同。
若相同返回 0;否则返回其他数。
该函数将两个字符串的字符一个一个来比较,直到遇到' \0 ',或者两字符不同为之。之后,返回当前两个字符的ASCII码差值(str1的字符 - str2的字符)。因此,两个相同的字符串,长度相同,' \0 '在同一位置。' \0 ' - ' \0 '结果就为0。
!!注意!!
要比较的两个字符串都要有’ \0 ',不然函数不知道什么时候停止比较,返回结果。
示例:
int main()
{char arr1[] = "def";char arr2[] = "def";char arr3[] = "defg";printf("arr1与arr2的比较结果为:%d\n", strcmp(arr1, arr2));printf("arr1与arr3的比较结果为:%d\n", strcmp(arr1,arr3));return 0;
}
运行结果:
错误示例(其中一个甚至两个字符串中都没有' \0 ',返回的结果是错误的):
strncpy、strncat、strncmp——限制长度的比较、连接和复制
它们的功能与前三者对应。strcpy——strncpy,strcat——strncat,strcmp——strncmp。
唯一的差别是它们比前者都多了一个参数,size_t num,作用是限制操作的个数(对应的就是限制比较字符个数,限制连接时拷贝的字符个数,限制复制个数)。
它们操作停止的标准不只是依照' \0 '了,还要看操作字符个数num了。这样一来多了个限制条件,能让操作更灵活。
!!注意!!
当num的值超过了字符串的长度时,可能会导致越界访问喔(其他注意事项同前三者)!
示例:
strtok——主字符串中提取字符串
定义:char * strtok ( char * str, const char * delimiters );
示例:
int main()
{char str[] = "- This, a sample string.";char* pch;printf("Splitting string \"%s\" into tokens:\n", str);pch = strtok(str, ",-. ");while (pch != NULL){printf("%s\n", pch);pch = strtok(NULL, ",-. ");}return 0;
}
由于这个函数的功能复杂,直接上图!
①
②
③在下一次使用时:
若传入的主字符串str不为NULL,则运行逻辑同上;
若传入的主字符串str为NULL,则上次运行创建的全局字符指针变量充当str。
运行结果:
通过多次使用strtok函数,实现将主字符串分割后提取小字符串。
最后主字符串str会变成:
!!注意!!
同样的,主字符串要有' \0 '。函数strtok找目标字符的停止条件是找到目标字符或者' \0 ',没有' \0 '可能会造成越界访问。
strsrt——模式串匹配
定义:const char * strstr ( const char * str1, const char * str2 );
功能:在串str1里找串str2,若找到,返回串str1内的str2的起始位置。
如str1为abcde,str2为cd,则返回str1中字符c的地址。
示例:
#include <stdio.h>
#include <string.h>int main ()
{char str[] ="This is a simple string";char * pch;pch = strstr (str,"simple");if (pch != NULL)strncpy (pch,"sample",6);puts (str);return 0;
}
程序中,通过strstr找到了主串里simple的位置,然后用strncpy把simple改成了sample。
运行结果:
!!注意!!
str1和str2都要有' \0 ',不然同样会在匹配时因为找不到' \0 '而停不下来,导致越界访问。
strerror——返回错误信息字符串。
定义:char * strerror ( int errnum );
功能:根据传入的错误码,返回对应的错误信息字符串。
错误码errno:每一个C程序运行时都会自行产生一个全局整型变量errno记录错误码。想要访问程序的错误码errno,就要包含头文件<errno.h>。
每一个错误码对应一条错误信息字符串,而这些字符串,在内存中都有地址。
(PS:在vs2022上,错误码的范围是0~42,若传入其他数字,会输出Unknown error,即未知的错误)
示例:
#include <stdio.h>
#include <string.h>int main()
{char* str = NULL;for (int i = 0; i < 21; i++){str = strerror(i);printf("错误码:%d—%s\n", i, str);}return 0;
}
该程序将错误码为0~20的错误信息都进行打印。
运行结果:
由图可知,程序没有出错,则错误码为0。
效果类似perror,不过perror可以自行获取错误码并自行打印错误信息,没有返回值。
memcpy——内存复制
定义:void * memcpy ( void * destination, const void * source, size_t num );
功能:将source中num个字节的内存数据复制到destination中。memcpy可以满足字符串复制strncpy的功能,也可以满足对其他类型数组之间的复制。
示例:
int main()
{char str[] = "abcedfg";char arr[] = "12345";memcpy(str, arr, 6);printf(str);return 0;
}
运行结果:
运行memcpy后,str在内存中:
!!注意!!
①目标内存和源内存的大小都要 >= 复制字节数num,否则会越界。
②复制什么时候结束,只看复制的字节数达到num了没有,不关注' \0 '。
③复制时,目标空间和源空间不可以重叠,不然会产生奇怪的结果(这一点产生的问题在VS的编译环境上被规避了,让其功能与memmove变得一模一样,即使重叠也不会有事,其他编译器不确定)。
memmove——内存挪移
这里不过多介绍,功能和定义都与memcpy相同,但是memmove在任何编译环境下都可以对重叠内存空间进行复制。
memset——设置内存
定义:void * memset ( void * ptr, int value, size_t num );
功能:将目标内存空间ptr中的前num个字节的值按value进行设置。
示例:
int main()
{char str[] = { 0,0,0,0,0,0,0,0,0,0,0 };memset(str, '6', 10);printf(str);return 0;
}
程序把字符全为' \0 '的字符串str中前10个字符设置为字符6,并输出。
运行结果:
!!注意!!
①设置内存的字节数num要 <= 目标空间的大小,不然会发生越界。
②该函数设置值得空间单位为1byte,但value为int类型,因此传入函数后会被截断,只要一个字节的数据,实际上设置的值大小范围为0x00~0xFF。
memcmp——以字节为单位比较数据
定义:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
功能:从ptr1和ptr2开始,以字节byte为单位比较num个字节byte内存中的数据。
示例:
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,0 };int arr2[] = { 1,2,3,4,5,6,7 };int arr3[] = { 1,2,3,4,5,6,7,8,9,9 };printf("arr1和arr2比较前6个数字的结果为:%d\n", memcmp(arr1, arr2, sizeof(int) * 6));printf("arr1和arr3比较前10个数字的结果为:%d\n", memcmp(arr1, arr3, sizeof(int) * 10));return 0;
}
运行结果:
memcmp返回值的结果和strcmp返回值逻辑一致。
!!注意!!比较字节数num要<=ptr1和ptr2的空间,不然会将内存中的随机值进行比较。vs也会报警告:读取无效数据。
结语:
关于字符函数和字符串函数的内容已经圆满完成!!
有什么疑问和困惑欢迎来评论区留言!!🤩我一定尽力及时解答!!制作不易,求关注!!求点赞!!之后还会有更多有用的干货博客会发出哦!!欢迎做客我的主页!!❤❤Elnaij-CSDN博客❤❤