一、strtok用法
strtok会首先过滤掉所有的属于分割字符串集合的字符,然后进行扫描并将之后碰到的属于分割字符串集合中的字符使用空结束符'/0'来替代,这样就可以直接使用该函数返回的直接读取第一个token(因为它读到'/0'就结束)。之后获取剩下的token的时候直接给strtok传递NULL作为第一个参数,从而不断取得下一个token。strtok提供的分隔符也可以为复数比如" ,.-",则遇到" "、","、“.”、"-"均进行分割。
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
strtok使用了一个静态变量,通过对该静态变量的操作来保证对指针的修改(基于上一个token的记录);除此之外,strtok另一个不太好的地方是它修改了原字符串,将对应位置替换为了'/0',这也是为什么这个函数的第一个参数不能是const char * 的原因。以下是strtok源码。
static char* ts=NULL;
char* strtok(char* s,const char* ct){
assert(s!=NULL&&ct!=NULL);
s=ts;//last position
if(!s&&*s==0)
return NULL;
char* t;
do{
for(t=ct,ts=NULL;*t;t++){
if(*t==*s){
if(*(ts=++s)) break;
return ts=NULL;
}
}
}while(ts);
for(ts=s;*ts;ts++)
for(t=ct;*t;t++)
if(*ts==*t){
*ts++='/0';
return s;
}
ts=NULL;
return s;
}
因为strtok函数使用了全局的静态变量,因此该函数是不可重入的,而且也不是线程安全的,因此在同一时间内多次使用该函数和多个线程使用该函数时会出现问题。由此产生了该函数的可重入版本:strtok_r,多出的一个r意即reentrant(可重入)。以下是strtok_r源码。
char * strtok_r(char *s1, const char *s2, char **lasts)
{
char *ret;
if (s1 == NULL)
s1 = *lasts;
while(*s1 && strchr(s2, *s1))//去掉前置分隔符
++s1;
if(*s1 == '/0')
return NULL;
ret = s1;
while(*s1 && !strchr(s2, *s1))
++s1;
if(*s1)
*s1++ = '/0';
*lasts = s1;
return ret;
}