strtok函式原始碼
阿新 • • 發佈:2019-02-05
今天用到strtok時,總感覺怪怪的,為啥第二次呼叫第一個引數要用NULL, 難道是函式內部儲存了當前的狀態,假如這樣的話,那就不能對多個串交叉呼叫strtok了,而且儲存這個狀態的不是全域性變數就是static變數。 於是看了他的原始碼,有幾個不同的版本,思想是一樣的。 感覺寫的挺巧妙的,深深的折服這些寫庫函式的牛人了。 下面是原始碼
版本一
char *s; /* string to search for tokens */ const char *delim; /* delimiting characters */ { static char *lasts; register int ch; if (s == 0) s = lasts; do { if ((ch = *s++) == '\0') return 0; } while (strchr(delim, ch)); --s; lasts = s + strcspn(s, delim); if (*lasts != 0) *lasts++ = 0; return s; }
上面用到了strcspn函式,這個函式返回值是n,表示s的前n個字元都沒有在delim中出現。原理是這樣的,函式在一開始判斷第一個引數是不是空,假如是的話,也就是第二次呼叫這個函數了,那麼把上一次的狀態last賦值給要返回的串,然後那個do實現的功能其實就是strspn函式,這個函式的返回值是n,代表 s的前n個字元全部在delim出現。也就是說do實現的是跳過s中字元屬於分隔符的字元。 然後通過下面的strcspn真正擷取需要的字元數。所以last就指向了下一個分隔符或者字元末尾。然後判斷last是否是末尾,假如不是的話,把當前的字元也就是分隔符標記成0,其實就是把前一段字元截斷了。last指向了下一個字元。 然後返回s。
版本二 把do直接用 strspn函式代替,思想一樣的
#include <string.h> /* strspn() strcspn() */ char *strtok(char * str, const char * delim) { static char* p=0; if(str) p=str; else if(!p) return 0; str=p+strspn(p,delim); p=str+strcspn(str,delim); if(p==str) return p=0; p = *p ? *p=0,p+1 : 0; return str; }
第三個版本直接是 沒有使用任何函式,用的是雜湊實現,這個雜湊的妙處真是沒誰了,這才是真正c語言程式好不好
char* strtok_r(char* string_org,const char* demial) {
static unsigned char* last;
unsigned char* str;
const unsigned char* ctrl = (const unsigned char*)demial;
unsigned char map[32];
int count;
for (count =0; count <32; count++){
map[count] = 0;
}
do {
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
} while (*ctrl++);
if (string_org){
str = (unsigned char*)string_org;
} else{
str = last;
}
while ((map[*str >> 3] & (1 << (*str & 7))) && *str){
str++;
}
string_org = (char*)str;
for (;*str; str++){
if ( map[*str >> 3] & (1 << (*str & 7))){
*str++ = '\0';
break;
}
}
last =str;
if (string_org == (char*)str){
return NULL;
}else{
return string_org;
}
}