目录
〇.先不多说,直接甩代码
后面有详解
char* my_strtok(char* str1, const char* str2)
{
assert(str2);
if (!*str2)
return str1;
char* s1 = str1;
char* s2 = (char*)str2;
static char* a = NULL;
if (!str1)
s1 = a;
while (*s1 && *s2)
{
if (*s1 == *s2++)
{
s1++;
s2 = (char*)str2;
}
}
if (!*s1)
return NULL;
a = s1;
while (*a)
{
s2 = (char*)str2;
while (*s2)
{
if (*a == *s2++)
{
*a++ = '\0';
return s1;
}
}
a++;
}
return s1;
}
一.简介strtok函数
char *strtok( char *strToken, const char *strDelimit );
strtok用于将字符串通过目标字符分割成一个个片段。参数strToken指向欲分割的字符串,参数strDelimit则包含用于分割字符串的所有目标字符。当strtok在参数strToken的字符串中发现参数strDelimit中包含的目标字符时,则会将该字符改为 '\0' 字符。
在第一次调用时,必需将参数strToken设置为想要分割的字符串,往后的调用则需将参数设置成NULL。每次调用成功则返回指向被分割出片段的指针。当strToken中的字符串查找到末尾后,再次调用返回NULL。
二.分步解释my_strtok
0.
char arr1[] = "nihao@woshi.zhangsan";
char arr2[] = "@.";
假设我想切割 nihao@woshi.zhangsan 字符串,目标字符是 @ 和 .
for (char* ret = my_strtok(arr1, arr2); ret != NULL; ret = my_strtok(NULL, arr2))
{
printf("%s\n",ret);
}
创建 ret 指针,利用 for 循环进行打印
1.定义
char* my_strtok(char* str1, const char* str2)
str1:第一次接收想要切割的字符串的地址,后接收NULL
str2:接收目标字符的字符串的地址,不需要改变加上const修饰
char* s1 = str1;
char* s2 = (char*)str2;
static char* a = NULL;
s1:返回值,最开始时记录目标字符串的地址
s2:记录目标字符的字符串的地址( (char*)强制将 const char* 类型转换为 char* 类型)
a:静态变量,作为标记,记录分割字符串后下一次调用的起始地址
2.条件
(一)
assert(str2);
断言,防止str2输入空指针
if (!*str2)
return str1;
如果目标字符未输入,则直接打印原字符串,不进行后续步骤
(此时,*str为空,即为假,! 后为真,判断成立)
(二)
if (!str1)
s1 = a;
if (!*s1)
return NULL;
第一个if:
当传入参数为NULL时,s1读取记录点
第二个if:
当s1指向的内容已经为空了,即已经查找到字符串末尾了,返回NULL,函数结束
(! 用法与上面相同,后续类似写法不在解释)
3.主体第一部分
while (*s1 && *s2)
{
if (*s1 == *s2++)
{
s1++;
s2 = (char*)str2;
}
}
if (!*s1)
return NULL;
作用
此部分有三个作用
一是:
如果字符串第一个字符便是目标,直接删去第一个字符,防止打印一个空行
假设 n 也是目标字符,如果不写此部分,就会出现下面的情况
二是:
如果字符串中,存在两个及以上的目标字符挨在一起,再次调用时,删去除去第一个以外的后面目标字符(第一个目标字符已在上次调用时删去)
假设 i 也是目标字符,如果不写此部分,就会出现下面的情况
三是:
条件(二)第二个if
解释
while (*s1 && *s2)
只有当s1和s2指向都不为空,循环才进行
if (*s1 == *s2++)
{
s1++;
s2 = (char*)str2;
}
判断s1指向的是否为目标字符,无论是不是,每进行一次判断s2都会++一次(即s2当前记录字符的地址改为下一字符的地址,比如一开始记录的 @ 的地址,++后改为 . 的地址,再++记录 \0 的地址),以此便可实现s1指向的字符与每一个目标字符进行比较
当s2指向 \0 时,为假,循环结束
当判断成立时,s1++指向下一个字符,s2重置,开始下一次循环判断s1指向的下一字符是否为目标字符
if (!*s1)
return NULL;
条件(二)第二个if
4.主体第二部分
a = s1;
while (*a)
{
s2 = (char*)str2;
while (*s2)
{
if (*a == *s2++)
{
*a++ = '\0';
return s1;
}
}
a++;
}
作用
该部分用于实现切割
解释
a = s1;
第一次调用时,a获取最初的字符串的地址
后续调用时:
1.条件(二)第一个if 处,已将s1赋值为a,此处a和s1指向本就相同
2.经过主体第二部分后,s1可能改变,此处重新让a和s1指向相同
while (*a)
{
s2 = (char*)str2;
while (*s2)
{
if (*a == *s2++)
{
*a++ = '\0';
return s1;
}
}
a++;
}
当a指向不为空时,开始循环
重置s2
开始判断a指向的是否为目标字符(写法与主体第一部分类似)
当判断为真,即a指向的是目标字符时,将该字符改为 \0 ,然后a++,指向字符串下一字符,然后返回s1,即切割下来的字符串的地址,函数结束
当a指向的不是任何一个目标字符时,a++,指向字符串下一字符,进入下一循环
最后
return s1;
到达这一步,说明a指向为空,从s1指向的字符到字符串的末尾这一串字符串是切割的最后一部分,返回s1,函数结束,下次再调用函数时就会返回NULL
程序结果
结束语
感谢大家的观看,如果有不足或错误欢迎提出!
求点赞求收藏求评论!