strsep和strtok_r替代strtok

时间:2023-03-08 16:42:10

char *strtok(char *str, const char *delim)

会修改数据源。外部加锁才线程安全(strtok执行结束再解锁执行另一个strtok循环知道工作完成)

主要是以互斥访问strtok实现文件中的static外部变量char*old。源码如下。

#include <string.h>

static char *olds;

#undef strtok

/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the last string strtok() was called with is
used. For example:
char s[] = "-abc-=-def";
x = strtok(s, "-"); // x = "abc"
x = strtok(NULL, "-="); // x = "def"
x = strtok(NULL, "="); // x = NULL
// s = "abc\0=-def\0"
*/
char *
strtok (s, delim)
char *s;
const char *delim;
{
char *token; if (s == NULL)
s = olds; /* Scan leading delimiters. */
s += strspn (s, delim);
if (*s == '\0')
{
olds = s;
return NULL;
} /* Find the end of the token. */
token = s;
s = strpbrk (token, delim);
if (s == NULL)
/* This token finishes the string. */
olds = __rawmemchr (token, '\0');
else
{
/* Terminate the token and make OLDS point past it. */
*s = '\0';
olds = s + ;
}
return token;
}

char *strsep(char **stringp, const char *delim)

会修改数据源。可重入的,注意这里虽然改动stringp的内容,主要是不在使用static静态变量了。

#include <string.h>

#undef __strsep
#undef strsep char *
__strsep (char **stringp, const char *delim)
{
char *begin, *end; begin = *stringp;
if (begin == NULL)
return NULL; /* A frequent case is when the delimiter string contains only one
character. Here we don't need to call the expensive `strpbrk'
function and instead work using `strchr'. */
if (delim[] == '\0' || delim[] == '\0')
{
char ch = delim[]; if (ch == '\0')
end = NULL;
else
{
if (*begin == ch)
end = begin;
else if (*begin == '\0')
end = NULL;
else
end = strchr (begin + , ch);
}
}
else
/* Find the end of the token. */
end = strpbrk (begin, delim); if (end)
{
/* Terminate the token and set *STRINGP past NUL character. */
*end++ = '\0';
*stringp = end;
}
else
/* No more delimiters; this is the last token. */
*stringp = NULL; return begin;
}

注意事项,会多次出现空字符串的问题,这是因为strsep在处理多于一个的delimit字符是会返回空字\0符串代替NULL(见源码便知),http://blog.****.net/striver1205/article/details/25601885

对比strtok,man手册提到:

The strsep() function was introduced as a replacement for strtok(3), since the latter cannot handle empty fields.
However, strtok(3) conforms to C89/C99 and hence is more portable.

stringp必须是二级指针,不能是指向字符数组的指针!

正确用法:

char a[]=......;char *p=a;strsep(&p,delim)

错误用法:

char a[]=...;strsep(&a,delim);会包参数类型错误

错误用法:

char *a=”xxxxx”;strsep(&a,delim)//错误,注意原串会被修改内容,字符常量会seg fault

char *strtok_r(char *str, const char *delim, char **saveptr)

会修改数据源。可重入,理由和strsep类似。