zoukankan      html  css  js  c++  java
  • strtok和strtok_r

    strtok和strtok_r

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

    功能:分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。

    说明:首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。
            strtok在s中查找包括在delim中的字符并用NULL('/0')来替换,直到找遍整个字符串。

    返回值:从s开头開始的一个个被切割的串。当没有被切割的串时则返回NULL。
               全部delim中包括的字符都会被滤掉,并将被滤掉的地方设为一处切割的节点。

    举例:

        #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;
       }

          函数第一次调用需设置两个參数。第一次切割的结果,返回串中第一个 ',' 之前的字符串,也就是上面的程序第一次输出abc。

          第二次调用该函数strtok(NULL,"."),第一个參数设置为NULL。结果返回切割根据后面的字串,即第二次输出d。

    带有_r的函数主要来自于UNIX以下。全部的带有_r和不带_r的函数的差别的是:带_r的函数是线程安全的,r的意思是reentrant,可重入的。

    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"//进入内循环

  • 相关阅读:
    LeetCode Find Duplicate File in System
    LeetCode 681. Next Closest Time
    LeetCode 678. Valid Parenthesis String
    LeetCode 616. Add Bold Tag in String
    LeetCode 639. Decode Ways II
    LeetCode 536. Construct Binary Tree from String
    LeetCode 539. Minimum Time Difference
    LeetCode 635. Design Log Storage System
    LeetCode Split Concatenated Strings
    LeetCode 696. Count Binary Substrings
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4084022.html
Copyright © 2011-2022 走看看