天天看点

strtok和strtok_r函数的使用

strtok()和strtok_r()都是以特定字符串为分隔符来分隔源字符串,是属于string函数家的族函数。

下面是基于实验得到的结论,实验环境为Linux Ubuntu11.04,gcc4.5.2。

1. strtok()函数

函数原型为:

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

该函数的返回值是char型指针,也就是要返回分隔后的字符串。

凡是返回指针的函数,可以推断该指针变量:

1) 通过malloc在函数中动态分配的。这类函数要注意调用完毕后手动free。鉴于这是一个库函数,若需要程序员调用

完该API后手动free,显得十分繁琐,所以这个返回的指针变量不是strtok函数中动态生成。

2) 返回形参的变量的地址。strtok的形参分别是指向待分解的源字符串和分隔符,返回形参的地址也不符合函数功

能。

3) 返回全局变量的地址。换句话说strtok把分割后的字符串放在一个全局变量中,并且把该地址返回给API调用者,确

实如此。

strtok()的使用方法是以*delim为分隔符,若str不为NULL,则查找str的第一个分隔符,将分隔符替换为’\0’,分隔符

前的字符串的首地址a和分隔符后的字符串的首地址b赋值给它自己维护的全局变量,并且返回该全局变量的b的地址;

若str为NULL,那么strtok()查找的起始位置则是自身维护的地址变量,它保存的是上次查找的分隔符后的首个元素的

地址。

验证程序: 分离/etc/passwd/文件中首行字符串。/etc/passwd是Linux记录用户名及密码的文件,在我的开发环境的

该文件的首行字符串为:

以”:”为分隔符,得到的字符串共有7个。

int main(void)
{
    FILE *fp = NULL;
    char buf[] = {};
    char *p = NULL;
    int i = ;
    char *info[] = {};

    //只读方式打开文件
    fp = fopen("/etc/passwd", "r");
    if (NULL == fp)
    {
        perror("perror");
        return -;
    }

    //获取fp指向的文件的一行字符串
    fgets(buf, sizeof(buf), fp);
    printf("fgets: %s", buf);

    p = buf;  //首次调用,要先把源字符串传进去
    //非首次调用,p为NULL传进去后,strtok会去自身备份的地址信息接着上一次的查找位置查找
    //每一次查找strtok返回的是分隔符前面的字符串的首地址
    while ((info[i++] = strtok(p, ":")) != NULL)  
        p = NULL;

    printf("buf = %s\n", buf);  

    for (i = ; i < ; i++){
        printf("info[%d] = %s\n", i, info[i]);
    }

    fclose(fp);
    return ;
}
           

运行结果:

strtok和strtok_r函数的使用

用表格的形式表现strtok的工作流程为:

strtok和strtok_r函数的使用

2. strtok_r()函数

strtok()函数是不可重入的,即在分隔一个字符串期间,函数返回后若去分隔另一个字符串,那么上一次的全局地址信息就会被覆盖。strtok_r()则是可重入的。原型为:

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

参数3是一个二级指针,也就是存放一级指针的地址。strtok_r同样是返回指针变量,与strtok不同的是,返回的地址

值不再是全局变量的地址,而是参数saveptr所指向的空间的地址了,该空间存放的是本次调用后分隔符前的字符串的

首地址。注意每次对strtok_r的调用都是针对形参str所指向的字符串。这样一来,API调用者可以自己在主调函数中维

护备份第3个实参了。

利用strtok_r()来实现上述功能为:

int main(void)
{
    FILE *fp = NULL;
    char buf[] = {};
    char *p = NULL;
    int i = ;
    char *info[] = {};

    //只读方式打开文件
    fp = fopen("/etc/passwd", "r");
    if (NULL == fp)
    {
        perror("perror");
        return -;
    }

    //获取fp指向的文件的一行字符串
    fgets(buf, sizeof(buf), fp);
    printf("fgets: %s", buf);

    info[] = buf;
    for (i = ; i < ; i++)
    {
        info[i] = strtok_r(info[i], ":", &info[i + ]);
    }

    for (i = ; i < ; i++)
    {
        printf("info[%d] = %s\n", i, info[i]);
    }

    fclose(fp);
    return ;
}
           

运行结果:

strtok和strtok_r函数的使用

用表格的形式表现strtok_r的工作流程为:

strtok和strtok_r函数的使用

上述便是我对strtok()和strtok_r()函数的理解。