C字符串分割(strtok和strtok_r)

时间:2022-11-12 19:12:12

先说说一个使用strtok经常遇见的问题:

 

char *str = "Fred John Micheal";

char buf[4];

int i = 0;

 

while((buf[i] = strtok(str, " ")) != NULL)

{

i++;

str = NULL;

}

 

上面这段代码在运行的时候会出现Segment fault,原因是strtok函数会改变第一个参数的值,而str是一个常量,所以会出错。

如果将str的定义做以下改变:

char str[100] = "Fred John Micheal";

结果就会正确了。

 

第一种声明方式虽然声明的也是一个字符串,str这个指针是放在堆栈区的,但是字符串的内容却是放在静态区的,所以是常量不能改变。

 

 

下面介绍一下strtok和strtok_r的实现原理:

 

1.strtok

函数原型:

char   *strtok(char   *str1,   char   *str2); 

 

strtok函数在实现的过程中使用了一个静态变量,在第一次截取了分隔符前面的字符串并返回以后,函数会修改原始字符串将分隔符位置的字符修改为"/0",静态变量会指向其后面的字符串的首字母。以后每次再截取的时候第一个参数设为NULL,就会不断的截取。

但是strtok函数的一个缺点就是修改了原始的字符串,将分隔符替换为了"/0",这也就是为什么函数的第一个参数不能为const的原因。而这个函数也因此不可重入,并且不是线程安全的。为此又有了可重入的版本,即strtok_r。

 

2.strtok_r

 

函数原型为:

char *strtok_r(char *s, const char *delim, char **ptrptr);

 

其中ptrptr变量替代了strtok函数中的静态变量的作用,用来传递一个指针的引用,也就是说截取以后生下字符串的首字母地址,因此不同的使用过程定义不同的指针变量传递进去就可以了,下面是个例子可以很清楚的理解:

 

 

#include<stdio.h>
#include<string.h>
#define INFO_MAX_SZ 255
int main()
{
   int in=0;
   char buffer[INFO_MAX_SZ]="Fred male 25,John male 62,Anna female 16";
   char *p[20];
   char *buf=buffer;

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

   while((p[in]=strtok_r(buf,",",&outer_ptr))!=NULL) {
             buf=p[in];
             while((p[in]=strtok_r(buf," ",&inner_ptr))!=NULL) {
                       in++;
                       buf=NULL;
                    }
                 p[in++]="***";
                 buf=NULL; }

   printf("Here we have %d strings/n",i);
   for (int j=0; jn<i; j++)
         printf(">%s</n",p[j]);
   return 0;
}

这一次的输出为:
Here we have 12 strings
>Fred<
>male<
>25<
>***<
>John<
>male<
>62<
>***<
>Anna<
>female<
>16<
>***<


让我来分析一下以上代码的运行过程:

红色为strtok_r的outer_ptr指向的位置
紫色为strtok_r的inner_ptr指向的位置
蓝色为strtok对字符串的修改

1. "Fred male 25,John male 62,Anna female 16" //外循环

2. "Fred male 25/0John male 62,Anna female 16"//进入内循环

3.   "Fred/0male 25/0John male 62,Anna female 16"

4   "Fred/0male/025/0John male 62,Anna female 16"

5 "Fred/0male/025/0John male 62,Anna female 16" //内循环遇到"/0"回到外循环

6   "Fred/0male/025/0John male 62/0Anna female 16"//进入内循环

 

 

 

以上内容参考:

http://blog.csdn.net/zhongnanhai/archive/2009/10/06/4637272.aspx

http://blog.chinaunix.net/u2/66402/showart_1168731.html