文章目录

  • 前言
  • 一、strtok函数是什么?
  • 二、字符串分割的步骤
  • 三、替代方案:strtok_r函数

前言

strtok 函数的作用是比较独特的,可以用来对字符串进行分割,对于我们获取命令或者数据集合后的数据处理是不可或缺的一步。但是详细介绍 strtok 的博文很少,而且linux手册的介绍也比较简单,这边写篇博文记录一下学习到的这个函数的用法。


一、strtok函数是什么?

函数定义如下:

strtok()函数,将字符串分解为一组字符串声明:char *strtok(char *str, const char *delim);头文件:#include <string.h>参数:str:源字符串指针,即分割之前的字符串delim:用于分割的字符串指针,即分割符号。如:空格" "、 逗号","、 字符集合"@."等 返回值:成功:返回指向被分割出片段的指针NULL:没有可被分割的字符串

即从字符串 str 中查找标记 delim 中出现的字符并以此切割字符串。注意原字符串 str 在函数调用完成后也会发生变化,变成分割后的第一个字符串。因此不能向第一个参数传递字符串常量,错误写法: char * str = "gonna be a string",应写成:char str[] = "gonna be a string"

二、字符串分割的步骤

在使用 strtok 函数时,第一次调用需要给定 str 参数的值,往后的每一次调用只需将 str 参数设置为 NULL 即可。我们通常使用 while 循环自动分割字符串的所有字符

  • 第一个参数不是 NULL 时,strtok 函数查找 str 下一个标记,以 \0 结尾,strtok 函数会保存标记的地址。
  • 第一个参数为 NULl 时,strtok 函数取上次分割字符串后剩余的字符串继续进行分解操作,如果没有更多的标记则返回 NULL

来举个例子:

#include #include "stdio.h"#include "string.h"int main() {char *temp = NULL;char input[128] = "#10?-ssid=test&-passwd=12345678&-netmask=255.255.255.0&-gateway=192.168.1.1";//char *input = (char *)malloc(128); //scanf("%s",input);printf("%s\n",input); temp = strtok(input,"?&");printf("input=%s,temp=%s\n", input, temp);while(temp != NULL){temp = strtok(NULL,"?&");printf("input=%s,temp=%s\n", input, temp);};return 0;}

输出结果:

#10?-ssid=test&-passwd=12345678&-netmask=255.255.255.0&-gateway=192.168.1.1input=#10,temp=#10input=#10,temp=-ssid=testinput=#10,temp=-passwd=12345678input=#10,temp=-netmask=255.255.255.0input=#10,temp=-gateway=192.168.1.1input=#10,temp=(null)

可以看到,我们传入的字符串以参数 delim 为依据对字符串进行了切割,其实就是把字符串 str 在参数 delim 中出现的字符替换成了 \0,并且返回标记字符串的首地址,了解到这一点,那么就可以使用 strtok(NULL,' '); 对字符串进行分离输出了。我们把该字符串分割的情况用图像展示出来,可以看到分割的依据是参数 delim 中的 每一个字符

所以在第一次分割后,str 的值会变成 #10 ,而后续的字符串需要我们用循环 strtok(NULL," "); 直至值为 NULL 来依照顺序把字符串提取出来。

char *strtok (char *s, const char *delim){static char *olds;return __strtok_r (s, delim, &olds);}char *__strtok_r (char *s, const char *delim, char **save_ptr){char *end;if (s == NULL)s = *save_ptr;//...}

通过源码可以看到,其实 strtok 函数是把分割后剩余的字符串存储在了静态变量中,当函数的第一个参数传入 NULL 时再提取出来进行分解。因为 static 静态变量是全局变量,这种方式在多线程操作时或发生中断的情况下容易引起冲突,所以Linux中可以使用更加安全的 strtok_r 函数进行替换。

三、替代方案:strtok_r函数

strtok 函数是一个线程不安全的函数,多线程时,linux下可以用 strtok_r 函数代替,该函数与 strtok 相似,主要是多了第三个参数 saveptr

函数定义如下:

strtok_r()函数,将字符串分解为一组字符串,同时保证线程安全声明:char *strtok_r(char *str, const char *delim, char **saveptr);头文件:#include <string.h>参数:str:源字符串指针,即分割之前的字符串delim:用于分割的字符串指针,即分割符号。如:空格" "、 逗号","、 字符集合"@."等 saveptr:保存分割后剩余的字符串返回值:成功:返回指向被分割出片段的指针NULL:没有可被分割的字符串

该函数的第三个参数 saveptr 使用用户传入的指针重新申请变量来保存剩余的字符串,更好的保存了切分时的上下文,因此该函数就能被中断而不担心会丢失数据,并且变量保存在每个函数自己的栈,因此可以同时运行该函数的多个副本,在并行环境中保证了安全性。