Linux C函数strtok解析

1. 今天看了看strtok函数,特意找了下Linux内核2.0.1版本的代码,因为在更高版本(至少2.6)已经使用strsep替换了该函数.

函数原型:

char * strtok(char * s,const char * ct)

使用第二个参数ct中的分隔符字符串,分割第一个参数s,ct参数的分隔符可以是任意字符,可以是单个字符的分隔符,也可以是字符串形式的分隔符如:"!,;'/"等,都可以作为分隔符。例如:

s="abc,def,123;456!/aaa"

ct=",;!/"

s将被分割为为:abc def 123 456 aaa

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  char s[] = "abc,def,123;456!/aaa";
  char delim[] = " ,;!/";

  char *p = NULL;
  for(p = strtok(s, delim); p != NULL; p = strtok(NULL, delim))
  {
    printf("%s ", p);
  }
  printf("\n");

  return 0;
}
[ljq@ycy algorithm]$ gcc strtok.c -o strtok
[ljq@ycy algorithm]$ ./strtok
abc def 123 456 aaa


2. strtok代码分析,以下代码摘自Linux2.01.版本:

char * strtok(char * s,const char * ct)
{
	char *sbegin, *send;

	sbegin  = s ? s : ___strtok;
	if (!sbegin) {
		return NULL;
	}
	sbegin += strspn(sbegin,ct);
	if (*sbegin == '\0') {
		___strtok = NULL;
		return( NULL );
	}
	send = strpbrk( sbegin, ct);
	if (send && *send != '\0')
		*send++ = '\0';
	___strtok = send;
	return (sbegin);
}

先说下strtok的整体思想也就是关键的几个步骤:

a。首先strtok将数据保存在全局变量__strtok中,因此不是线程安全的也即不可重入。

b。strtok查找分隔符字符串时,跳过连续的分隔符,这样可以忽略连续分隔符之间的空串,连续分隔符是从源字符串开始位置计算,个数通过函数strspn计算得出。

      size_t strspn(const char *s, const char *accept),计算字符串 str 中连续有几个字符都属于字符串 accept。

      例如:";,/!ABC!/DEF",前四个字符都是分隔符且是连续的,那么strspn函数返回4,有效数据跳过前4个分隔符就从字符A开始,直到下一分隔符。

c。调用函数strpbrk,即源字符串中的字符如果与分隔符字符串中任意字符相同,就返回指向源字符串中该字符的指针,即找到了分隔符,返回该数据的指针。

      char * strpbrk(const char * cs,const char * ct),比较字符串str1和str2中是否有相同的字符,如果有,则返回该字符在str1中的位置的指针。

      例如:";,/!ABC!/DEF",跳过4个分隔符后,从A开始直到遇到分隔符感叹号(!) 那么,就返回指向数据起始位置的指针,该指针指向字符A。


细节分析:

a。 变量__strtok是全局变量,定义在string.c文件中:char * ___strtok = NULL; 在头文件linux/string.h中进行外部声明,只要使用该变量的c文件包含该头文件即可;

b。全局变量__strtok保存了剩余未做分隔的字符串的起始地址,每次调用strtok函数,都从全局变量__strtok指向的地址开始查找参数中的分隔符字符串,找到之后__strtok指向本次分隔符的下一位置(有效数据或者结尾符\0,又或者是分隔符如果有连续分隔符的话)。

c。对于字符串 "abc,def,123;456!/aaa"; 第一次调用strtok之后,分隔符逗号(,)被设置为\0,__strtok设置为指向第一个分隔符逗号之后的数据即__strtok指向字符d,返回指向字符a的指针;第二次调用strtok时,从__strtok指向的字符d开始查找delim中的分隔符,找到第二个逗号时,与第一次操作一样,分隔符逗号被设置为\0,并从新设置__strtok指向字符1,返回指向字符d的指针,后续一直如此循环。

d。如果源字符串包含连续分隔符,则调用函数strspn计算出连续相同的分隔符字符后会跳过这些分隔符。


附上函数strspn的测试示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  int ret = 0;
  char s1[] = "abc,;!/}defgh,,,**#123,456";
  char s2[] = ";,/#}*abc,;!/}defgh,,,**#123,456";
  char delim[] = ",;!/}#*";

  ret = strspn(s1, delim);
  printf("ret1:%d\n", ret);

  ret = strspn(s2, delim);
  printf("ret2:%d\n", ret);

  return 0;
}

结果如下:

[ljq@ycy algorithm]$ gcc strspn.c -o strspn
[ljq@ycy algorithm]$ ./strspn              
ret1:0
ret2:6

函数是从源字符串开始位置匹配分隔符,只有开始的连续才起作用,开始有1个或者多个则返回匹配到的分隔符个数,如果开始位置一个分隔符都没有,则返回0,如果有1个则返回1个,上例中返回6个。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

种菜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值