在C语言的学习中,我们经常会遇到字符串,对它的处理也是数不胜数,但是我们没有很好的处理办法,字符串只能放在字符数组或常量字符串中通过自定义函数去使用处理。而现在我将带领大家学习C语言函数库中专门处理字符串的函数。
这些处理字符串的函数全部放在#include<string.h>和#include<type.h>中使用!接下啦让我们具体认识一下这些函数!!!
string.h中的函数介绍
strlen函数
strlen函数是获取字符串函数大小(作用)
1.返回值类型是size_t(无符号整数)
2.参数是接收一个不可修改的char*类型的指针
3.参数指向的字符串必须要以 '\0' 结束。
4.strlen函数返回值是返回字符串的长度,当指针指向'\0'时结束计数,所以字符串的长度不包括'\0'。
下面一段程序使用strlen函数:
#include <stdio.h> int main() { const char*str1 = "abcdef"; const char*str2 = "bbb"; if(strlen(str2)-strlen(str1)>0) { printf("str2>str1\n"); } else { printf("srt1>str2\n"); } return 0; }
代码分析很明显str1的字符串长度为6,str2的字符串长度为3,3-6=-3理应输出结果为str1>str2,但实际结果为:
这是为什么呢?因为strlen函数返回的类型为无符号整型,所以两数相减默认结果也为无符号整型,-3在二进制存储中的补码非常大,但是计算机却认为-3的补码就是它的原码,所以换算为十进制将会是一个非常大的正数,所以结果输出结果出现了错误。
如果我们将if条件判断中的条件换成(strlen(str2)>strlen(str1));结果就会正确!
下面我们来创建自定义函数,模拟实现strlen函数 。
//模拟strlen函数 size_t my_strlen(char* arr) { int count = 0; while (*arr != '\0') { count++; arr++; } return count; } int main(void) { char arr[100]; gets(arr); printf("%u\n", my_strlen(arr)); return 0; }
我们仿照strlen函数中的参数以及返回值以及原理模拟出my_strlen函数。具体是传入我们要求字符数组的首元素,创建一个临时变量count用来计传入数组的个数,利用while循环判断指针是否指向'\0',如果没有指向count++、arr++进行计数和指针向后移动,直到走到'\0'处跳出循环,返回count的数即可实现strlen函数的模拟。
strcpy函数
srtcpy函数是将源指向的字符串复制到指向的数组中;
1.返回值是一个char*的指针,指向复制字符串的首元素地址。
2.参数为两个char*类型的指针,后面那个是被复制的字符串,所以不能被修改,前面的是复制的字符串。
3. 源字符串必须以'\0'结束。
4.目标空间必须足够大,确保能存放源字符串。
5.目标空间必须可变。
6.此函数会将源字符串中的'\0'拷贝到目标空间中。
下面是对strcpy函数的使用:
int main(void) { char arr1[100]; char arr2[100] = "hello world"; char* p = strcpy(arr1, arr2); printf("%s\n", p); return 0; }
将arr2中的字符串拷贝到arr1中去。
下面是对strcpy函数的模拟:
模拟strcpy函数 char* my_strcpy(char* p1, const char* p2) { assert(p1 && p2); char* ret = p1; while (*p1++ = *p2++) { ; } return ret; } int main(void) { char arr1[100]; char arr2[100]; gets(arr2); char* p = my_strcpy(arr1, arr2); printf("%s\n", p); return 0; }
我们的目的还是将arr2中的内容拷贝到arr1中,创建自定义函数my_strpy函数仿照strcpy函数的函数模板,使用assert函数进行断言,防止传入的指针为空指针。创建一个字符指针来标记目标数组的首元素地址用来作为返回值。利用while循环进行条件判断如果p2不为'\0‘则进行*p1=*p2赋值,赋值成功后两个指针全部向后移动一位,直到p2为'\0'结束循环即可完成复制(操作可以简化到while语句的判断条件中),最后将目标数组的地址返回即可。
结果如下:
strcat函数
strcat函数是连接字符串的函数,将已知字符串连接到目标字符串。
1.返回值是目标字符串的首元素地址
2.两个参数是char*类型的字符指针,后面的指针是已知字符串元素首地址不能修改,所以用const修饰,前面指针是目标字符串的首地址。
3.源字符串必须以 '\0' 结束。
4.目标空间必须有足够的大,能容纳下源字符串的内容。
5.目标空间必须可修改。
下面是对strcat函数的使用:
int main(void) { char arr1[20] = "hello "; char arr2[20] = "world"; char* p = strcat(arr1, arr2); printf("%s\n", p); return 0; }
strcat函数的原理:找到目标字符串'\0'处进行覆盖,加入已知字符串到目标字符串的尾部,直到已知字符串的'\0'处结束,返回目标字符串的首元素指针。
最后是对strcat函数的模拟实现:
char* my_strcat(char* p1, const char* p2) { assert(p1 && p2); char* ret = p1; while (*p1 != '\0') p1++; while (*p1++ = *p2++) { ; } return ret; } int main(void) { char* arr1[100]; char* arr2[100]; gets(arr1); gets(arr2); char* p = my_strcat(arr1, arr2); printf("%s\n", p); return 0; }
目标是把已知字符串放到目标字符串的末尾,所以我们接收到两个指针时,先标记目标函数的首元素为最后返回值做准备,然后我们利用while循环将目标字符串的指针指到末尾'\0'处,然后进行的操作就和strcpy函数的原理一样,进行复制,最后将目标函数的首元素返回即可完成。
以下是代码运行结果:
strcmp函数
strcmp函数是比较两个字符串大小的函数。
1.返回值为int类型的数
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
2.参数为两个比较的字符串,为了使保护两个字符串无意被修改,所以都用const修饰。
3.此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续以下对,直到字符不同或达到终止空字符。
下面是对strcmp函数的使用:
int main(void) { char arr1[100] = "hello"; char arr2[100] = "hell"; printf("%d\n", strcmp(arr1, arr2)); return 0; }
hello与hell这两个字符串,前面hell全部相等,只有最后一个o与'\0'进行比较大小,根据ascaii码值o比'\0'大,所以arr1字符串比arr2字符串大,返回1。
最后对strcmd函数模拟实现:
//模拟实现strcmp函数 int my_strcmp(const char* p1, const char* p2) { assert(p1 && p2); while (*p1 == *p2) { p1++; p2++; } if (*p1 - *p2 > 0) return 1; else if (*p1 - *p2 < 0) return -1; else return 0; } int main(void) { char arr1[100]; char arr2[100]; gets(arr1); gets(arr2); printf("%d\n", my_strcmp(arr1, arr2)); return 0; }
将两个字符串传入函数中,使用while循环进行比较(*p1 == *p2)如果相等就让两个指针都向后挪动一位继续比较,如果相同则返回0,如果*p1>*p2则返回1,*p1<*p2则返回-1即可。
以下是运行结果:
strstr函数
strstr函数的作用就是查找子字符串。子字符串为str2,目标字符串为str1。
1.返回值为char*类型的指针,返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。
2.参数类型为两个字符指针,分别指向目标字符串和子字符串,因为不能被修改所以加入const进行修饰。
3.匹配过程不包括终止空字符,但它到此为止。
下面是我们对strstr函数的使用:
int main(void) { char arr1[100] = "hello world"; char arr2[100] = "lo"; char* p = strstr(arr1, arr2); printf("%s\n", p); return 0; }
上面是对子字符串lo在目标字符串hello world中的查找,当查找到时,将返回从lo开始的字符串开始打印,结果应该是:lo world。那我们来看一下结果是否与我们设想的相同呢?
运行结果与我们设想相同。
下面我们进行对strstr函数的模拟实现:
//模拟strstr函数 char* my_strstr(const char* p1, const char* p2) { char* ret = p1; char* w = p2; char* flag = NULL; while (*ret != '\0') { if (*ret == *w) { flag = ret; while (*w != '\0') { if (*ret != *w) { w = p2; ret = flag; flag = NULL; break; } w++; ret++; } } ret++; } return flag; } int main(void) { char* arr1[100]; char* arr2[100]; gets(arr1); gets(arr2); char* p = my_strstr(arr1, arr2); printf("%s\n", p); return 0; }
此函式仿照strstr函数的参数以及返回值进行模拟,因为要找到子函数对应在目标函数的位置,所以我们得创建一个char*类型的临时指针用来标记,然后先利用while循环找出目标函数与子函数的首个内容相同,用指针刚才创建的指针进行首元素标记,然后再嵌套一个循环进行全部内容比较,如果全部相同则返回刚才指针标记的地址,如果不相同则子函数指针返回到最初,目标函数继续进行往下一个位置进行比较,直到找到完成目标即可,若是没找到子函数内容则返回空指针。
运行结果如下:
strtok函数
strtok函数是将字符串拆分函数,是将一整个字符串按照所给的分割符号拆开。
1.delimiters参数是个字符串,定义了用作分隔符的字符集合。
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL 指针。
strtok函数在第一次调用时,会将找到的字符作为标记,如果我们第二次调用此函数时给第一个参数传入空指针时,strtok函数会在上一次传入的字符串中继续寻找目标字符,并且将其分割。所以一般使用此函数时会和for循环进行结合使用。
具体使用方法:
int main(void) { char arr[] = "zhangsan@year.com.cn"; char sep[] = "@."; char copy[50]; strcpy(copy, arr); char* ret = NULL; for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep)) { printf("%s\n", ret); } return 0; }
运行结果如下:
更加严谨的库函数
上面我们学习了strcpy、strcat、strcmp函数,他们都比较关注'\0‘,但是不会关注追加的字符,我们把这些函数叫做长度不受限制的字符串函数。接下来我们接收一些长度受限制的字符串函数。
分别是strncpy、strncat、strnmp函数,比之前学习的函数多了个n,那函数原型与之前有什么区别呢?
他们都是比之前的函数原型多一个参数size_t num,这个num就限制了需要的字符。功能和之前的函数完全相同。
那为什么说它们更加严谨呢?
strncpy函数
int main(void) { char arr1[20] = "abcdef"; char arr2[] = "xxxxxxxxxxxxxxxx"; strncpy(arr1, arr2, 3); return 0; }
虽然arr2中的字符串很长,但我们只拷贝三个字符进入arr1中去。
如果我们的arr2中的字符串中只有三个字符,但是在strncpy中我们第三个参数写入5,会是怎么样呢?
剩下没有的会用'\0'来替换,直到满足拷贝5个为止。
但是strncat函数就不一样了!!!
strncat函数
int main(void) { char arr1[20] = "abcdef'\0'yyyyy"; char arr2[] = "xxx"; strncat(arr1, arr2, 5); return 0; }
因为strncat函数与strcat函数原理基本相同,在遇到'\0'时会停下然后追加字符串,如果我们给予一个正常字符串时,后面全是'\0'看不到追加字符不够时的变化,所以我们用这种特殊的字符串进行调试!
由此调试,我们可以看出strncat与strncpy的不同,strncat函数不管字符够不够,只要把已知的字符添加完成最后在加入’\0'即可。
strncmp函数
strncmp函数与strcmp函数功能相同,就是由size_t num限制比较个数,用法也是非常简单,我就举一个程序:
int main(void) { char arr1[100] = "abdefghigk"; char arr2[100] = "abdfgiigk"; printf("%d\n", strncmp(arr1, arr2, 2)); printf("%d\n", strncmp(arr1, arr2, 4)); return 0; }
小结
总的来说,带n的比不带n的更加安全,因为它们限制了大小,我们在使用的时候就会注意数组空间是否能存储下等等一系列问题。
但是在正常使用下,两种类型的函数都是一样的,一个人想写bug是拦不住的!!!
ctype.h中的函数介绍
ctype.h中的函数是处理字符的函数,只要我们能记住这些函数套着去使用就可以了!!!
下面是ctype.h中一些重要函数:
字符判断函数:
函数 | 如果他的参数符合下列条件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
字符转换函数:
int tolower ( int c ); 转大写
int toupper ( int c );转小写
具体使用方法:
#include <stdio.h> #include <ctype.h> int main () { int i=0; char str[]="Test String.\n"; char c; while (str[i]) { c=str[i]; if (isupper(c)) c=tolower(c); putchar (c); i++; } return 0; }
分析:将字符串中的小写字符转成大写。
以上是我对基本字符串函数与字符函数的描述,对博主有不足的地方可以在评论区留言,博主会耐心学习,你们的支持是我最大的动力!!!