關於LINUX C中函數strtok使用要點

strtok函數的使用是一個老生常談的問題了。該函數的作用很大,爭議也很大。以下的表述

使用的源代碼大部分來自於網絡,我稍加修改作爲例證。當然,本人水平有限,有不妥之處望各位多多指教。

strtok的函數原型爲char *strtok(char *s, char *delim),功能爲“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. ” 翻譯成漢語就是:作用於字符串s,以包含在delim中的字符爲分界符,將s切分成一個個子串;如果,s爲空值NULL,則函數保存的指針SAVE_PTR在下一次調用中將作爲起始位置。

函數的返回值爲從指向被分割的子串的指針。

要點紀要:

1.函數的作用是分解字符串,所謂分解,即沒有生成新串,只是在str所指向的內容上做了些手腳而已。因此,源字符串str發生了變化!

下面就以str[] = "ab,c,d"爲簡單案例一代嗎來證實其str發生了變化:


 

點擊(此處)摺疊或打開

  1. #include <string.h> 
  2. #include <stdio.h>

  3. int main(void)
  4. {
  5.   char str[] = "ab,c,d";
  6.   char *= NULL;
  7.   char delim = ",";

  8.   int in = 0;
  9.   p = strtok(str, delim);
  10.   while(!= NULL){
  11.     printf("the character is :%s\n",p);
  12.     printf("the str is : %s\n",str);
  13.     p = strtok(NULL,delim);
  14.   } 
  15. }

代碼執行後輸出結果:

 

點擊(此處)摺疊或打開

  1. the character is : ab
  2. the str is : ab
  3. the character is : c
  4. the str is : ab
  5. the character is : d
  6. the str is : ab

有上面的結果可知,str發生了變化。此時打印str的值,只會顯示“ab”,而後面" ,c,d”不翼而飛了。實際上,strtok函數根據delim中的分界符,找到其首次出現的位置,即ab後面那個空格(str[2]),將其修改成了'\0’。其餘位置不變。這就很好解釋爲什麼打印str的值只能出現“ab”,而非str中的全部內容了。因此,使用strtok時一定要慎重,以防止源字符串被修改。 

理解了str的變化,就很好解釋函數的返回值了。返回值delim爲分界符之前的子串;由變量的地址可知,p依然指向源字符串。

 

2.若要在第一次提取子串完畢之後,繼續對源字符串s進行提取,應在其後(第二次,第三次。。。第n次)的調用中將strtok的第一個參數賦爲空值NULL。

第一次之後的調用我們都給strtok的第一個參數傳遞了空值NULL(表示函數繼續從上一次調用隱式保存的位置,繼續分解字符串;對於上述的第二次調用來說,第一次調用結束前用一個this指針指向了分界符的下一位,即'c’所在的位置),這樣可依次提取出 "c d",加入你感覺爲什麼非要賦空值,我如果不賦空繼續賦值爲str會有什麼結果。其實,答案想也能想的到。再一次傳遞str,相當於還從字符串的開頭查找分界符delim,而且此時str已經被修改(可見的部分只剩下"ab"),因此,其結果必然是找不到分界符delim只是打印出ab後面的就沒有辦法打印出來了。

 

 

3.分隔符delim的探討(delim是分隔符的集合)
很多人在使用strtok的時候,都想當然的以爲函數在分割字符串時完整匹配分隔符delim,比如delim=”ab”,則對於"acdeab”這個字符串,函數提取出的是"acde”。至少我在第一次使用的時候也是這麼認爲的。其實我們都錯了,我是在看函數的源代碼時才發現這個問題的,且看下面的例子

點擊(此處)摺疊或打開

  1. int main(void)
  2. {
  3.   char str[] = "acdeab";
  4.   char *= NULL;
  5.   int in = 0;
  6.   p = strtok(str, "ab");
  7.   while(!= NULL){
  8.     printf("the character is :%s\n",p);
  9.     p = strtok(NULL,"ab"); 
  10.   } 
  11. }

輸出的結果爲:

  1. the character is :cde

第一次調用之後的結果竟然是"cde”,而非我們所想的結果。這是爲什麼呢?

我們回到GNU C Library中對strtok的功能定義:“Parse S into tokens separated by characters in DELIM”。也就是說包含在delim中的字符均可以作爲分隔符,而非嚴格匹配。可以把delim理解爲分隔符的集合。這一點是非常重要的

當然,我們在分解字符串的時候,很少使用多個分隔符。這也導致,很多人在寫例子的時候只討論了一個分隔符的情況。有更多的人在看例子的時候也就錯誤的認識了delim的作用。

4.待分解的字符串,首字符就爲分隔符

首字符爲分隔符不能算作一個很特殊的情況。按照常規的分解思路也能正確分解字符串。

由此說明的是,strtok對於這種情況採用了比常規處理更快的方式。

僅用一次調用就可以得到以“ab”分隔的字符串"acdeab”,而前面的a被忽略了。由此可見,strtok在調用的時候忽略了起始位置開始的分隔符。這一點,可以從strtok的源代碼得到證實

6.不能向第一個參數傳遞字符串常量!

本文中所舉的例子都將源字符串保存爲字符串數組變量。若你將源字符串定義成字符串常量,可想而知,程序會因爲strtok函數試圖修改源字符串的值,而拋出異常。

 

對於該函數的使用我也就理解到這裏,如果還有其他的用法以後發現再來完善吧。


轉自 http://blog.chinaunix.net/uid-26681200-id-3139269.html

發佈了171 篇原創文章 · 獲贊 68 · 訪問量 229萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章