strtok和strtok_r


原型:char *strtok(char *s, char *delim); 小程序

功能:分解字符串爲一組字符串。s爲要分解的字符串,delim爲分隔符字符串。 安全

說明:首次調用時,s指向要分解的字符串,以後再次調用要把s設成NULL。
        strtok在s中查找包含在delim中的字符並用NULL('/0')來替換,直到找遍整個字符串。
函數

返回值:從s開頭開始的一個個被分割的串。當沒有被分割的串時則返回NULL。
           全部delim中包含的字符都會被濾掉,並將被濾掉的地方設爲一處分割的節點。
spa

舉例: 線程

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

    int main(void


        char input[16] = "abc,d"

        char *
p; 

   /*
 strtok places a NULL terminator 
        in front of the token, if found 
*/
 
        p = strtok(input, ","
); 
        if (p)      printf("%s "
, p); 

   /*
 A second call to strtok using a NULL 
        as the first parameter returns a pointer 
        to the character following the token  
*/
 
        p = strtok(NULL, ","
); 
        if (p)      printf("%s "
, p); 
指針

        return 0
   }
token

      函數第一次調用需設置兩個參數。第一次分割的結果,返回串中第一個 ',' 以前的字符串,也就是上面的程序第一次輸出abc。

      第二次調用該函數strtok(NULL,"."),第一個參數設置爲NULL。結果返回分割依據後面的字串,即第二次輸出d。
字符串

帶有_r的函數主要來自於UNIX下面。全部的帶有_r和不帶_r的函數的區別的是:帶_r的函數是線程安全的,r的意思是reentrant,可重入的。
input

1. strtok介紹
衆所周知,strtok能夠根據用戶所提供的分割符(同時分隔符也能夠爲複數好比「,。」)
將一段字符串分割直到遇到"/0".

好比,分隔符=「,」 字符串=「Fred,John,Ann」
經過strtok 就能夠把3個字符串 「Fred」     「John」      「Ann」提取出來。
上面的C代碼爲

原型

QUOTE:
int in=0;
char buffer[]="Fred,John,Ann"
char *p[3];
char *buf = buffer;
while((p[in]=strtok(buf,","))!=NULL) {
                 in++;
                 buf=NULL; }

如上代碼,第一次執行strtok須要以目標字符串的地址爲第一參數(buf=buffer),以後strtok須要以NULL爲第一參數 (buf=NULL)。指針列p[],則儲存了分割後的結果,p[0]="John",p[1]="John",p[2]="Ann",而buf就變成    Fred/0John/0Ann/0。

2. strtok的弱點
讓咱們更改一下咱們的計劃:咱們有一段字符串 "Fred male 25,John male 62,Anna female 16" 咱們但願把這個字符串整理輸入到一個struct,

QUOTE:
struct person { 
     char [25] name ; 
     char [6] sex;
     char [4] age;
}

要作到這個,其中一個方法就是先提取一段被「,」分割的字符串,而後再將其以「 」(空格)分割。
好比: 截取 "Fred male 25" 而後分割成 "Fred" "male" "25"
如下我寫了個小程序去表現這個過程:

QUOTE:
#include<stdio.h>
#include<string.h>
#define INFO_MAX_SZ 255
int main()
{
   int in=0;
   char buffer[INFO_MAX_SZ]="Fred male 25,John male 62,Anna female 16";
   char *p[20];
   char *buf=buffer;

   while((p[in]=strtok(buf,","))!=NULL) {
             buf=p[in];
             while((p[in]=strtok(buf," "))!=NULL) {
                       in++;
                       buf=NULL;
                    }
                 p[in++]="***"; //表現分割
                 buf=NULL; }

   printf("Here we have %d strings/n",i);
   for (int j=0; j<in; j++)
         printf(">%s</n",p[j]);
   return 0;
}

這個程序輸出爲:
Here we have 4 strings
>Fred<
>male<
>25<
>***<
這只是一小段的數據,並非咱們須要的。但這是爲何呢? 這是由於strtok使用一個static(靜態)指針來操做數據,讓我來分析一下以上代碼的運行過程:

紅色爲strtok的內置指針指向的位置藍色爲strtok對字符串的修改

1. "Fred male 25,John male 62,Anna female 16" //外循環

2. "Fred male 25/0John male 62,Anna female 16" //進入內循環

3.    "Fred/0male 25/0John male 62,Anna female 16"

4.    "Fred/0male/025/0John male 62,Anna female 16"

5 "Fred/0male/025/0John male 62,Anna female 16" //內循環遇到"/0"回到外循環

6   "Fred/0male/025/0John male 62,Anna female 16" //外循環遇到"/0"運行結束。

3. 使用strtok_r
在這種狀況咱們應該使用strtok_r, strtok reentrant. 
char *strtok_r(char *s, const char *delim, char **ptrptr);

相對strtok咱們須要爲strtok提供一個指針來操做,而不是像strtok使用配套的指針。
代碼:

QUOTE:
#include<stdio.h>
#include<string.h>
#define INFO_MAX_SZ 255
int main()
{
   int in=0;
   char buffer[INFO_MAX_SZ]="Fred male 25,John male 62,Anna female 16";
   char *p[20];
   char *buf=buffer;

   char *outer_ptr=NULL;
   char *inner_ptr=NULL;

   while((p[in]=strtok_r(buf,",",&outer_ptr))!=NULL) {
             buf=p[in];
             while((p[in]=strtok_r(buf," ",&inner_ptr))!=NULL) {
                       in++;
                       buf=NULL;
                    }
                 p[in++]="***";
                 buf=NULL; }

   printf("Here we have %d strings/n",i);
   for (int j=0; jn<i; j++)
         printf(">%s</n",p[j]);
   return 0;
}

這一次的輸出爲:
Here we have 12 strings
>Fred<
>male<
>25<
>***<
>John<
>male<
>62<
>***<
>Anna<
>female<
>16<
>***<


讓我來分析一下以上代碼的運行過程:

紅色爲strtok_r的outer_ptr指向的位置
紫色爲strtok_r的inner_ptr指向的位置
藍色爲strtok對字符串的修改

1. "Fred male 25,John male 62,Anna female 16" //外循環

2. "Fred male 25/0John male 62,Anna female 16"//進入內循環

3.   "Fred/0male 25/0John male 62,Anna female 16"

4   "Fred/0male/025/0John male 62,Anna female 16"

5 "Fred/0male/025/0John male 62,Anna female 16" //內循環遇到"/0"回到外循環

6   "Fred/0male/025/0John male 62/0Anna female 16"//進入內循環

相關文章
相關標籤/搜索