文章目录
- 前言
- 一、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
使用用户传入的指针重新申请变量来保存剩余的字符串,更好的保存了切分时的上下文,因此该函数就能被中断而不担心会丢失数据,并且变量保存在每个函数自己的栈,因此可以同时运行该函数的多个副本,在并行环境中保证了安全性。