編程時在C中需要用的類似Java的Split函數來解析一個長字符串,分割成子段使用,查函數庫發現有strtok可用,看了示例卻對它的用法有些疑惑為什么傳值是NULL,于是上網查資料,找到這篇包含strtok函數源碼的解釋,轉過來學習,仔細研讀收獲良多。
查函數庫看到的strtok的解釋和示例:
strtok
Syntax:
#include <cstring> char *strtok( char *str1, const char *str2 );
The strtok() function returns a pointer to the next "token" in str1, where str2 contains the delimiters that determine the token. strtok() returns NULL if no token is found. In order to convert a string to tokens, the first call to strtok() should have str1 point to the string to be tokenized. All calls after this should have str1 be NULL.
For example:
char str[] = "now # is the time for all # good men to come to the # aid of their country";
char delims[] = "#";
char *result = NULL;
result = strtok( str, delims );
while( result != NULL ) {
printf( "result is /"%s/"/n", result );
result = strtok( NULL, delims );
}
The above code will display the following output:
result is "now "
result is " is the time for all "
result is " good men to come to the "
result is " aid of their country"
下面是查到的網絡文章對源碼的解釋:
原型:char * strtok(char * s,const char * ct)
用途:在s中找出以ct中的字符為分隔的字符串,即是源串中除去了含有分隔串中的所有字符后余下的一段段的字符串,每調用一次找到一串,找不到則返回空串。第一次調用必須傳給它有效的字符串,第二次傳NULL就可以了,每次調用返回找到的子串的時候都會把源串中該子串的尾部字符(原來是搜索串中的某一字符)修改成'/0'字符返回值為每次調用得到的字串。
下面看一下它的使用
char sbody[]= "Presetptz/r/nPreset1=hello/r/nPreset2=ttttt/r/nend/r/n";
///char *pbody= "Presetptz/r/nPreset1=hello/r/nPreset2=ttttt/r/nend/r/n";//errror
char except[] = "12/r/n";
char *ptoken = NULL;
ptoken = strtok(sbody,except);
while(NULL!=ptoken)
{
printf("%s/n",ptoken);
ptoken = strtok(NULL,except);
}
輸出為:
Presetptz
Preset
=hello
Preset
=ttttt
end
下面我們看一下它的源碼:
char *___strtok;//關鍵這個全局指針變量
char * strtok(char * s,const char * ct)
{
char *sbegin, *send;
sbegin = s ? s : ___strtok;//不等于NULL用原始字符串,否則用___strtok
if (!sbegin) {
return NULL;//結尾
}
sbegin += strspn(sbegin,ct);//
if (*sbegin == '/0') {
___strtok = NULL;
return( NULL );
}
send = strpbrk( sbegin, ct);
if (send && *send != '/0')
*send++ = '/0';
___strtok = send;
return (sbegin);
}
其中: ssize_t strspn(const char* s,char*accept)// 返回accept中任一字符在s中第一次出現的位置
char * strpbrk(const char * cs,const char * ct)//返回指向ct中任一字符在cs中第一次出現的位置
這個函數不難分析,___strtok指針指向除去第一個有效字串后面的位置,到這里我們應該清楚為什么第二次調用時只要傳NULL就可以了,當然這里也暴露了它的缺點,就是說不能有兩個線程同時使用strtok否則就會出現錯誤。還有就是我在使用這個函數時碰到的問題,如上面的代碼如果我把sbody換成 pbody,則編譯沒有問題,運行時就會出錯,為什么?還是自己的基本功不扎實,pbody在是個靜態字符串,說白了,它是在編譯時就已經賦值而且相當于是一個const常量,不能被修改,而strtok是需要修改字符串的,所以產生問題不足為奇。