歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> Linux C函數strtok解析

Linux C函數strtok解析

日期:2017/3/3 12:28:34   编辑:Linux技術

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個。

Copyright © Linux教程網 All Rights Reserved