头文件<string.h>
char *strtok(char s[], const char *delim);
用于分隔字符串,常用于网络编程中分隔ip地址
分隔完最后一个词后,再次调用会返回NULL(n个词调用n次)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[]="123,456,789";
printf("%d,%d\n",sizeof(a),strlen(a));
char *b=strtok(a,",");
printf("%d,%d\n",sizeof(a),strlen(a));
printf("%d,%d\n",sizeof(b),strlen(b));
printf("%s\n",a);
printf("%s\n",b);
b=strtok(NULL,",");
printf("%d,%d\n",sizeof(a),strlen(a));
printf("%d,%d\n",sizeof(b),strlen(b));
printf("%s\n",a);
printf("%s\n",b);
printf("\n");
char c[]="abc,efg,hij";
printf("%d,%d\n",sizeof(c),strlen(c));
b=strtok(c,",");
printf("%d,%d\n",sizeof(c),strlen(c));
printf("%d,%d\n",sizeof(b),strlen(b));
printf("%s\n",c);
printf("%s\n",b);
b=strtok(NULL,",");
printf("%d,%d\n",sizeof(c),strlen(c));
printf("%d,%d\n",sizeof(b),strlen(b));
printf("%s\n",c);
printf("%s\n",b);
return 0;
}
结果:
通过上面的实验, 可知:
1.当调用strtok时必须把一个目标分隔完成后再分隔下一个,
2.第一次分隔调用 strtok(a,","),之后分隔调用strtok(NULL,",");
3.调用strtok是在原有的字符数组上进行修改,不会减小原字符数组的长度
4.经实验,多个分隔符在一起会被当成一次分隔处理。
结论,对于编程要注意的:
1.应在分隔前检查分隔符是否非法,比如192…168…17…2
int mark=1;
int count=0;
while(*p!='\0')
{
if(*p==',') count++;
else count=0;
if(count>1)
mark=0;//有错误
}
if(mark==1)
{ 正常操作}
2.进行分隔时要使用循环一次行进行分隔
例如:
char a[]="123,456,789";
char c[5][10];
memset(c[0],0,5*10*sizeof(char));
int j=0;
b=strtok(a,",");
strcpy(c[j++],b);
while(b!=NULL)
{
b=strtok(NULL,",");
if(b==NULL)
break;
strcpy(c[j++],b);
}
strtok 和平常的使用的函数似乎不太一样,好像能记住上一次调用他的情况,这是因为strtok中有个静态的指针指向上次分隔时的下一个位置,当第一个参数有值时,使用第一个参数作为待分隔的字符串,而当第一个参数为NULL,则使用内置的静态指针作为 待分隔的字符串。
补充:
在引入异步之后,
当进程在main() 中执行了strtok 后,如果在信号处理中也调用了strtok,则 当对应的信号出现时,进入信号处理函数,然后返回main()中执行,此时,main()中,strtok内置的静态指针和程序原本期望的静态指针就会发生混乱。(还有插入链表的例子,main中插入一个链表节点,插到一半,来了个信号,也要插入节点,也会发生混乱)
这种在处理中断或者捕捉信号中调用特别的函数而导致的错误,就是因为特别的函数是不可重入的,或者叫做线程不安全的。应该禁止在中断或者信号捕捉函数中调用这类函数。
当由于在中断或者信号捕捉函数中调用这类函数出现bug时,bug的复现情况是随机的,当程序正常执行到某个位置,并且在此时收到某种刺激(中断、信号),这个bug才会复现,而这种情况概率很小,所以一旦出现这种bug,解决起来比较费劲
strtok也因此被称为是不安全的。
为了解决strtok 线程不安全这个问题,c标准库的string.h 中又加入了一个相似的线程安全的版本
前两个参数,以及返回值 ,都和strtok相同,不同之处在于,原来的静态指针的值,变成了保存到第三个参数中。用户可以将第三个参数保存起来,每次调用时,将第三个参数当成第一个参数重新传入
使用方法
char buf[20] = "hello world abc cba";
char *a = buf;
char *b = NULL;
while(NULL != (b = strtok_r(a, " ", &a))){
printf("%s\n",b);
}
输出: