strtko_r和strsep函数都是Linux下面的字符串切割函数,但是使用时有许多地方需要注意,分析库里的函数实现源码可以帮助我们更好的使用该函数。
1.strtko_r函数源码
由于众多的版本。这里strtok_r函数源码来自于GNU C Library:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the saved pointer in SAVE_PTR is used as
the next starting point. For example:
char s[] = "-abc-=-def";
char *sp;
x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
x = strtok_r(NULL, "=", &sp); // x = NULL
// s = "abc\0-def\0"
*/
char* strtok_r(char *s, const char *delim, char **save_ptr) {
char *token;
if (s == NULL) s = *save_ptr;
/* Scan leading delimiters. */
s += strspn(s, delim);//
//这句话的作用是跳过开始第一个字符就是分隔符的情况;
if (*s == '\0')
return NULL;
/* Find the end of the token. */
token = s;
s = strpbrk(token, delim);
if (s == NULL)
/* This token finishes the string. */
*save_ptr = strchr(token, '\0');//函数strchr 在参数 token 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置
//返回一个指向该字符串中第一次出现的字符的指针,如果字符串中不包含该字符则返回NULL空指针
else {
/* Terminate the token and make *SAVE_PTR point past it. */
*s = '\0';
*save_ptr = s + 1;
}
return token;
}
int main()
{
char tmp[] ="-abc-=-def";
char* ptr;
char *rc = strtok_r(tmp,"-",&ptr);
printf("%s\n",rc);
rc = strtok_r(NULL,"=-",&ptr);
printf("%s\n",rc);
return 0;
}
这里主要注意源码里strspn 和 strbrp函数,理解了这两个函数的作用就理解了strtko_r源码。
s += strspn(s, delim);
函数strspn返回 s 中第一个不在字符串 deklim 中出现的字符下标。若strspn()返回的数值为n,则代表字符串s 开头连续有n 个字符都是属于字符串delim内的字符,这句话的作用是跳过开始第一个字符就是分隔符的情况;
s = strpbrk(token, delim);
函数strpbrk依次检验字符串 token 中的字符(不包含空结束字符),即将token中的每个字符和delim中的每个字符比对,当被检验字符(delim中的字符)在字符串 token 中也包含时,则停止检验,并返回该字符位置,如果未找到字符则返回 NULL。
这句话的作用是在被分割字符串中查找分隔符,如果找到将指针指向该处; 后面将该处的分隔符替换成字符串结束符。
2. strsep函数源码
函数原型 char *strsep(char **stringp, const char *delim);
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no moretokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *strsep(char **stringp, const char *delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp)== NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc =*spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}