目录
一. 前言
C语言在标准库中提供了标准的字符串操作函数,可用于查找字符串中的字符、子字符串等。这给程序员提供了很大的便利,并且有利于提高程序的可移植性。本文对C语言标准库中提供的常见字符串查找相关函数进行了解读,并进行了模拟实现。
二. 查找一个字符
2.1 库函数strchr
2.1.1 strchr的函数原型及实现的功能
函数原型:char *strchr( const char *string, int c );
函数功能:在字符串string中查找一个字符c,并返回指向第一次出现c的位置的指针,如果字符串string中没有字符c,那么就返回空指针NULL。
函数参数:
- string:被查找的字符串
- c:想要在字符串中查找的字符,这里c采用int型是因为字符本质上是其对应的ASCII码值,字符型变量也属于整型家族。int型变量长度为4字节,char型为1字节,因此使用int型变量接受char型变量完全没有问题。
使用库函数strchr要引用头文件<string.h>
2.1.2 strchr的使用方法演示
代码段2.1在字符串 arr1[ ] = "abcdeccf"中查找第一次出现字符'c'的位置,程序运行的结果:cdeccf
代码段2.1:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdeccf";
char* ret = strchr(arr1, 'c');
printf("%s\n", ret); //cdeccf
return 0;
}
2.1.3 strchr的模拟实现
strchr的模拟实现代码:
char* my_strchr(const char* str, int c)
{
assert(str); //指针有效性检验
while (*str != '\0')
{
if (c == *str) //查找到c就返回c的位置
{
return str;
}
str++;
}
return NULL; //找不到c就返回NULL
}
2.2 库函数strrchr
2.2.1 strrchr的函数原型及可以实现的功能
函数原型:char *strrchr( const char *string, int c );
函数功能:在字符串string中查找字符c最后一次出现的位置
函数参数:
- string:被查找的字符串
- c:期望在string中查找的字符
函数的返回值:若在string中查找到c,则返回c最后一次出现的位置,若没有查找到c,就返回空指针NULL。
2.2.2 strrchr的使用方法演示
代码段2.2实现的功能是在字符串arr1[]="abcdeccf"中查找字符c最后一次出现的位置,程序运行的结果为:cf
代码段2.2:
int main()
{
char arr1[] = "abcdeccf";
char* ret = strrchr(arr1, 'c');
printf("%s\n", ret); //cf
return 0;
}
2.2.3 strrchr的模拟实现
模拟实现代码:
char* my_strrchr(const char* str, int c)
{
assert(str);
char* ret = NULL; //初始化返回值为NULL
while (*str != '\0')
{
if (c == *str) //在str中遇到c就将其位置暂时存入ret
{
ret = str;
}
str++;
}
return ret;
}
三. 查找任何几个字符
3.1 strpbrk函数
3.1.1 strpbrk的函数原型和实现的功能
函数原型:char *strpbrk( const char *string, const char *strCharSet );
函数功能:在字符串string中查找第一次出现strCharSet字符串中任何一个字符的位置。
函数参数:string是被查找的字符串,strCharSet为期望在string中查找的字符的集合
函数返回值:若在string中查找到了strCharSet中任意一个字符,则返回指向第一次出现这个字符的位置的指针,若找不到这样的一个字符,则返回空指针NULL。
3.1.2 strpbrk函数使用方法的演示
代码段3在arr1中寻找第一次出现group字符串中任意一个元素的位置,程序运行的结果为:deccf
代码段3.1:
int main()
{
char arr1[] = "abcdeccf";
char group[] = "dhj";
char* ret = strpbrk(arr1, group);
printf("%s\n", ret); //deccf
return 0;
}
3.1.3 strpbrk的模拟实现
模拟实现代码:
char* my_strpbrk(const char* str, const char* group)
{
assert(str && group); //指针有效性检验
while (*str != '\0')
{
//调用库函数strchr,再group中查找*str,若不返回NULL,则找到了这样一个字符
if (strchr(group, *str) != NULL)
{
return str;
}
str++;
}
return NULL; //找不到,返回空指针
}
四. 查找一个子字符串
4.1 strstr函数
4.1.1 strstr的函数原型及实现的功能
函数原型:char *strstr( const char *s1, const char *s2);
函数功能及返回值:在s1中查找整个s2第一次出现的起始位置,并返回一个指向该位置的指针,如果s2没有出现在s1的任何地方,函数将返回一个NULL指针。如果第二个参数是一个空字符串,就返回s1。
4.1.2 strstr函数的使用方法演示
代码段4.1在字符串arr1[]="abcdecdf"中查找"cd"第一次出现的位置,程序的运行结果为:cdecdf
代码段4.1:
int main()
{
char arr1[] = "abcdecdf";
char arr2[] = "cd";
char* ret = strstr(arr1, arr2);
printf("%s\n", ret); //cdecdf
return 0;
}
4.1.3 strstr函数的模拟实现
模拟实现代码:
char* my_strstr(const char* str1, const char* str2)
{
assert(str1); //指针有效性检验
if (str2 == NULL) //str2是空字符串就返回str1的位置
{
return str1;
}
size_t len2 = strlen(str2); //求arr2中含有几个有效字符
while (*str1 != '\0')
{
//比较str1和str2的前len2个字符是否相同
//如果相同,返回此时str1的位置
if (strncmp(str1, str2, len2) == 0)
{
return str1;
}
str1++;
}
return NULL;
}
五. 查找一个字符串的前缀
5.1 strspn函数
5.1.1 strspn的函数原型及实现的功能
函数原型:size_t strspn( const char *str, const char *group );
函数功能:group字符串指定一个或多个字符。strspn返回str起始部分匹配group中任意字符的字符数。例如,arr1[] = "1234.56@abcf",arr2[] = "12389",字符串arr1中的第1、第2、第3个字符可以在arr2中找到,arr1中第4个字符无法在arr2中找到,因此,strspn(arr1,arr2)的返回值为3。
5.1.2 strspn函数的使用方法演示
在代码段5.1中定义了三个字符串,分别为:arr1[] = "12.34.56@abcf"、arr2[] = "123456"、arr3[] = ".123456",先后执行语句strspn(arr1,arr2)和strspn(arr1,arr3),arr1的前2个字符可以在arr2中找到匹配,arr1中前8个字符可以在arr3中找的匹配。因此,程序中ret1=2,ret2=8。
代码段5.1:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "12.34.56@abcf";
char arr2[] = "123456";
char arr3[] = ".123456";
size_t ret1 = strspn(arr1, arr2);
printf("%u\n", ret1); //2
size_t ret2 = strspn(arr1, arr3); //8
printf("%u\n", ret2);
return 0;
}
5.1.3 strspn函数的模拟实现
模拟实现代码:
size_t my_strspn(const char* str, const char* group)
{
assert(str && group); //指针有效性检验
size_t count = 0; //str其实位置与group中任意字符匹配的字符数
while (strchr(group, *str) != NULL)
{
//在group中查找*str,若不返回NULL,则表示*str这个字符可以与group中其中之一匹配
//匹配成功就进行count++操作
count++;
str++;
}
return count;
}
5.2 strcspn函数
5.2.1 strcpn的函数原型及实现的功能
函数原型:size_t strcspn( const char *str, const char *group );
函数功能:strcspn函数的功能与strspn正好相反,它计算字符串str起始部分有几个字符无法与group中任意一个字符匹配。比如,arr1[]="123.456.78.90@abcd",arr2[ ]="@abc",arr1前面的123.456.78.90(共13个字符)与arr2无法匹配,因此,strcspn(arr1,arr2)返回的结果为12。
5.2.2 strcspn的使用方法演示
代码段5.2中定义两个字符串arr1和arr2,指向语句strcspn(arr1, arr2),arr1中的前12个字符无法与arr2中任意一个字符匹配,因此程序运行的结果为13。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "123.456.78.90@abcd";
char arr2[] = "@abc";
size_t ret = strcspn(arr1, arr2);
printf("%u\n", ret); //13
return 0;
}
5.2.3 strcspn函数的模拟实现
模拟实现代码:
size_t my_strcspn(const char* str, const char* group)
{
assert(str && group); //指针的有效性检验
size_t count = 0;
while (strchr(group, *str) == NULL)
{
//调用库函数strchr,在group函数中查找不到*str就返回NULL,执行count++
count++;
str++;
}
return count;
}
六. 查找字符串中的标记
6.1 strtok函数
6.1.1 strtok的函数实现的功能及函数原型
函数原型:char *strtok( char *strToken, const char *strDelimit );
函数功能:通过查找标识符,将一个字符串分隔开来,并将标识符丢弃,将源字符串标识符的位置替换为'\0'。
函数参数:strDelimit字符串定义了分隔符的集合,strToken包含零个或多个strDelimit字符串中定义的分隔符。函数在strToken查找strDelimit定义的分隔符,并将分隔符替换为\0。
函数的返回值:若在字符串中查找到了标记,就返回被标记的位置,若找不到标记,就返回空指针NULL。
注意:若strtok的第一个参数不是NULL,函数将找到字符串的第一个标记,同时,strtok函数将保存第一个标记在字符串中的位置。若strtok的第一个参数为NULL,则从上一次标记被保存的位置开始查找下一个标记。
6.1.2 strtok的使用方法演示
注意:由于strtok函数会改变原来的字符串,因此,一般将字符串的一份临时拷贝传入到strtok函数中。
在代码段6.1中,定义了字符串arr1[]="123.456.789@abc#def" 和分隔符集合group[]=".@#",程序在arr1中查找分隔符.#@并打印被分隔的每一块,程序的运行结果为:123 456 789 abc def。
代码段6.1:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "123.456.789@abc#def";
char arr[25] = { 0 };
strcpy(arr, arr1); //取一份arr1的临时拷贝
char group[] = ".#@";
char* ret = arr;
for (ret = strtok(arr, group); ret != NULL; ret = strtok(NULL, group))
{
printf("%s ", ret); //123 456 789 abc def
}
return 0;
}
警告:由于strtok函数具有记忆功能,因此,在同一循环内不能用strtok函数同时处理两个字符串,不可以循环条件使用strtok函数,循环体内的语句也使用strtok函数。
6.1.3 strtok函数的模拟实现
模拟实现代码:
char* my_strtok(char* str, const char* group)
{
static char* remember = NULL; //记忆字符串位置
char* start = NULL; //定义并初始化开始查询的位置
if (str == NULL)
{
//若第一个参数为NULL,则从上次查找的的分隔符位置开始查询下一个分隔符
start = ++remember;
}
else
{
//若第一个参数不为NULL,则从这个参数指向的位置开始查询
start = str;
}
assert(start); //此时,不再运行start为空指针,要进行指针有效性检验
size_t leng = strlen(group) + 1; //group的字符数(包含末尾\0)
char* pos = strpbrk(start, group); //求start后第一次出现分隔符的位置
if (NULL != pos)
{
*pos = '\0';
remember = pos; //记忆分隔符的下一个内存位置
return start; //返回开始查找的位置
}
else
{
return NULL;
}
}
全文结束,感谢大家的阅读,敬请批评指正。