C字符串分割 - strtok 與 strtok_r

C字符串分割 - strtok 與 strtok_r
http://hi.baidu.com/alexin163/blog/item/f1ad5287bed5eb2dc65cc388.html

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 *buff = buffer;
while((p[in]=strtok(buf,","))!=NULL) {
    i++;
    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"//進入內循環


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章