++这篇博客为你归纳了所有的字符函数和最常用的字符串函数,以及对应的模拟实现!!你可以直接循着目录跳到你需要的段落哦!!++😍
目录
strncpy、strncat、strncmp------限制长度的比较、连接和复制
字符函数
字符函数分为两类:++字符判断和字符转换++ 。它们都包含在*++头文件<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 '。++
示例:
cpp
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 '。++
示例:
cpp
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 '。++
示例:
cpp
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 "(垂直制表符)。++
示例:
cpp
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 '是若干个 ' '(空格)。
示例:
cpp
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 '。++
示例:
cpp
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 '。++
示例:
cpp
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 '++
示例:
cpp
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------判断标点圆形符号
功能:判断是否为标点圆形符号,++~ ! @ # $ % ^ & * ( ) _ + = - ` [ ] \ { } | ; ' : " , . / < > ?。++
即键盘上除了数字、字母、控制符和空白符之外,所有的*++英文++*圆形标点符号。
示例:
cpp
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------判断圆形字符
功能:判断是否为圆形字符。++除了空白符和控制字符外,其余符号都为圆形字符。++
示例:
cpp
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------判断可打印的字符
功能:判断是否为可打印字符。所有的++字母、数字、空格++(其他空白符可不算喔)、**++英文圆形标点符号++**都是可打印字符。
示例:
cpp
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 '**不属于控制字符,但是属于空白符。
示例:
cpp
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------小写字母转大写
功能:将小写字母转换为大写,并返回转换结果。如果传入的不是小写字母,就返回传入的字符。
示例:
cpp
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------大写字母转小写
功能:将大写字母转为小写,并返回转换结果。如果传入的不是小写字母,就返回传入的字符。
示例:
cpp
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编译器会报警告。)
示例:
cpp
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函数。
②目标字符串要有足够的空间接受源字符串的复制,多出来的字符仍然会越界赋值。同样是危险的操作。
示例:
cpp
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会让这样的死循环停止,但是还是会产生奇怪的结果,所以还是不要这么做了)。
示例:
cpp
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 ',不然函数不知道什么时候停止比较,返回结果。
示例:
cpp
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 );
示例:
cpp
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的地址。
示例:
cpp
#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,即未知的错误)
示例:
cpp
#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的功能,也可以满足对其他类型数组之间的复制。
示例:
cpp
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进行设置。
示例:
cpp
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内存中的数据。
示例:
cpp
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博客❤❤