关于strtok 函数的说明

admin2024-04-03  0

目录

strtok 函数介绍:

代码示例:

关于strtok_r的介绍:


strtok 函数介绍:

头文件:
函数strtok在<string.h>中。

函数定义:

char * strtok ( char * str, const char * delim );

str:要分割的字符串

delim:用于分割的字符集合 

strtok函数原理与使用方法:
第一次调用:strtok(char *s,char *delim),其中字符串delim是分隔识别符,在s中寻找首次出现在delim中的字符,把该字符替换为\0。如果找不到,不对原字符串进行改变。

第二次调用:把第一个参数设为NULL,第二个参数含义不变。strtok(char *s,NULL)。

返回值:
每次的返回值返回分隔后的下一个字符串的首地址。注意,分隔完成后原字符串已经被被改变了。

Note: 首先该函数是不可重入函数,是线程不安全函数,使用时,一定要慎用。

代码示例:

下面的代码中,我们可以看到这两行代码:

        char buf[200] ={};
        strcpy(buf,p);

这里为什么要把p 拷贝到新的buf中,因为strtok 会改变原字符串,所以在内循环中调用strstok 的话最好不要使用原字符串,而是通过将原来的字符串拷贝到新的buf中。

#include<fstream>
#include<ostream>
#include<string>
#include<stdio.h>
#include <string.h>
#include<stdlib.h>

using namespace std;

void test(void)
{
    std::string primaryStr = "Number,19_29_39,9,49_59";
    char * s_input = const_cast<char*>(primaryStr.c_str());
    const char * split = ",";

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

    char* p = strtok_r(s_input, split,&outer_ptr);
    bool additionFlag = true;


    while (p != NULL)
    {
        p = strtok_r(NULL, split,&outer_ptr);
        printf("start:%s\n",p);
        if (p == NULL)
            continue;

        char buf[200] ={};
        strcpy(buf,p);

        if (strstr(p, "0x"))
        {
            printf("0x%s\n",p);
        }
        else
        {
            if (fcpAdditionFlag)
            {
                const char* slotSplit = "_";
                for (char* str = strtok_r(buf, slotSplit,&inner_ptr); str != NULL; str = strtok_r(NULL, slotSplit,&inner_ptr))
                {
                    std::string strSlot(str);
                    printf("str: %s %d\n",p,std::stoi(strSlot));
                }
                continue;
            }
            else
            {
                printf("d:%s\n",p);
            }
        }
    }
}


int main()
{
   test();
   return 0;
}

打印结果:

下面的代码是将前面说的两行代码注释掉,在内循环中strstok 直接使用p 源字符串。

#include<fstream>
#include<ostream>
#include<string>
#include<stdio.h>
#include <string.h>
#include<stdlib.h>

using namespace std;

void test(void)
{
    std::string primaryStr = "Number,19_29_39,9,49_59";
    char * s_input = const_cast<char*>(primaryStr.c_str());
    const char * split = ",";

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

    char* p = strtok_r(s_input, split,&outer_ptr);
    bool additionFlag = true;


    while (p != NULL)
    {
        p = strtok_r(NULL, split,&outer_ptr);
        printf("start:%s\n",p);
        if (p == NULL)
            continue;

        //char buf[200] ={};
        //strcpy(buf,p);

        if (strstr(p, "0x"))
        {
            printf("0x%s\n",p);
        }
        else
        {
            if (additionFlag)
            {
                const char* slotSplit = "_";
                for (char* str = strtok_r(p, slotSplit,&inner_ptr); str != NULL; str = strtok_r(NULL, slotSplit,&inner_ptr))
                {
                    std::string strSlot(str);
                    printf("str: %s %d\n",p,std::stoi(strSlot));
                }
                continue;
            }
            else
            {
                printf("d:%s\n",p);
            }
        }
    }
}


int main()
{
   test();
   return 0;
}

打印结果:

对比前面两份代码的打印结果,可以发现如果内存不使用新的buf 得话,p 指针会被改变。

另外需要注意的是:上述示例代码我其实已经将strstok替换成strstok_r 了。

关于strtok_r的介绍:

char *strtok_r(char *str, const char *delim, char **saveptr);

strtok_r函数是strtok函数的可重入版本。str为要分解的字符串,delim为分隔符字符串。char **saveptr参数是一个指向char *的指针变量,用来在strtok_r内部保存切分时的上下文,以应对连续调用分解相同源字符串。

第一次调用strtok_r时,str参数必须指向待提取的字符串,saveptr参数的值可以忽略。连续调用时,str赋值为NULL,saveptr为上次调用后返回的值,不要修改。一系列不同的字符串可能会同时连续调用strtok_r进行提取,要为不同的调用传递不同的saveptr参数。

strtok_r实际上就是将strtok内部隐式保存的this指针,以参数的形式与函数外部进行交互。由调用者进行传递、保存甚至是修改。需要调用者在连续切分相同源字符串时,除了将str参数赋值为NULL,还要传递上次切分时保存下的saveptr。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!