首先看第一个strtok:

虽然strtok有诸多问题,已经被Linux kernel淘汰,由strsep替代,但了解这个函数的实现对我们理解C语言的运用极有裨益,也有过知名企业的面试中甚至出现了strtok函数的实现考察。

C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。

这个函数陷阱很多,我们先看一下这个函数一个实现(来源于apple opensource):

#include <stddef.h>
#include <string.h>char *
strtok(s, delim)register char *s;register const char *delim;
{register char *spanp;register int c, sc;char *tok;static char *last;if (s == NULL && (s = last) == NULL)return (NULL);/** Skip (span) leading delimiters (s += strspn(s, delim), sort of).*/
cont:c = *s++;for (spanp = (char *)delim; (sc = *spanp++) != 0;) {if (c == sc)goto cont;}if (c == 0) {      /* no non-delimiter characters */last = NULL;return (NULL);}tok = s - 1;/** Scan token (scan for delimiters: s += strcspn(s, delim), sort of).* Note that delim must have one NUL; we stop if we see that, too.*/for (;;) {c = *s++;spanp = (char *)delim;do {if ((sc = *spanp++) == c) {if (c == 0)s = NULL;elses[-1] = 0;last = s;return (tok);}} while (sc != 0);}/* NOTREACHED */
}

strtok内部的last指针是static,记录上次调用字符串的位置,所以不支持多线程,可重入版本为strtok_r,所以不要使用strtok这个函数,除非100%确定无多线程同时调用,无重入问题:

/* Parse S into tokens separated by characters in DELIM.If S is NULL, the saved pointer in SAVE_PTR is used asthe next starting point.  For example:char s[] = "-abc-=-def";char *sp;x = strtok_r(s, "-", &sp);        // x = "abc", sp = "=-def"x = strtok_r(NULL, "-=", &sp);        // x = "def", sp = NULLx = strtok_r(NULL, "=", &sp);        // x = NULL// s = "abc\0-def\0"
*/
char *
__strtok_r (char *s, const char *delim, char **save_ptr)
{char *end;if (s == NULL)s = *save_ptr;if (*s == '\0'){*save_ptr = s;return NULL;}/* Scan leading delimiters.  */s += strspn (s, delim);if (*s == '\0'){*save_ptr = s;return NULL;}/* Find the end of the token.  */end = s + strcspn (s, delim);if (*end == '\0'){*save_ptr = end;return s;}/* Terminate the token and make *SAVE_PTR point past it.  */*end = '\0';*save_ptr = end + 1;return s;
}

glibc中还是保留了strtok的实现,但是也就是对strtok_r的封装,在封装外侧做了static的操作:

/* Parse S into tokens separated by characters in DELIM.If S is NULL, the last string strtok() was called with isused.  For example:char s[] = "-abc-=-def";x = strtok(s, "-");                // x = "abc"x = strtok(NULL, "-=");                // x = "def"x = strtok(NULL, "=");                // x = NULL// s = "abc\0=-def\0"
*/
char *
strtok (char *s, const char *delim)
{static char *olds;return __strtok_r (s, delim, &olds);
}

Linux kernel2002年抛弃strtok函数,直接上的strsep函数替代,更精简,更高效:

 /** linux/lib/string.c** Copyright (C) 1991, 1992 Linus Torvalds*//** stupid library routines.. The optimized versions should generally be found* as inline code in** These are buggy as well..** * Fri Jun 25 1999, Ingo Oeser* - Added strsep() which will replace strtok() soon (because strsep() is* reentrant and should be faster). Use only strsep() in new code, please.** * Sat Feb 09 2002, Jason Thomas ,* Matthew Hawkins* - Kissed strtok() goodbye*/

kernel中strtok都被替换成了strsep,而且还温馨的添加了注释:

/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */

strsep的实现:

/*** strpbrk - Find the first occurrence of a set of characters* @cs: The string to be searched* @ct: The characters to search for*/
char * strpbrk(const char * cs,const char * ct)
{const char *sc1,*sc2;for( sc1 = cs; *sc1 != '\0'; ++sc1) {for( sc2 = ct; *sc2 != '\0'; ++sc2) {if (*sc1 == *sc2)return (char *) sc1;}}return NULL;
}/*** strsep - Split a string into tokens* @s: The string to be searched* @ct: The characters to search for** strsep() updates @s to point after the token, ready for the next call.** It returns empty tokens, too, behaving exactly like the libc function* of that name. In fact, it was stolen from glibc2 and de-fancy-fied.* Same semantics, slimmer shape. ;)*/
char * strsep(char **s, const char *ct)
{char *sbegin = *s, *end;if (sbegin == NULL)return NULL;end = strpbrk(sbegin, ct);if (end)*end++ = '\0';*s = end;return sbegin;
}

这段代码非常精简,而且还很有趣,我们来一起分析一下:

注意:其中,strpbrk函数 检索返回字符串 cs中第一个匹配字符串 ct 中字符的字符位置。

用一段测试代码来说明:

int main()
{char string[] = "192.168.0.199";char *str = string;char *p;while((p = my_strsep(&str, "."))) {printf("%s\n", p);}return 0;
}

string是一个字符数组,str是一个指向string的字符指针,p是一个字符指针,用于保持my_strsep每次的返回指针并打印。

首先调用my_strsep函数,传入字符指针的地址和分隔符。

my_strsep函数中sbegin指向s指向的字符数组

strsep函数中调用strpbrk传入sbegin指针,返回分隔符位置,然后strsep函数返回分隔符的下一个位置,即由分隔符分隔的下一段字符串。

s是一个指向指针的指针,地址是(char ***) 0x7fffffffe628, s指向的指针的地址是 (char **) 0x7fffffffe650,这个地址就是字符数组的地址。

sbegin是一个字符指针,地址(char **) 0x7fffffffe630,它指向s所指向的地址0x7fffffffe65a 。

my_strsep函数就是调用strpbrk函数获取到分隔位置,然后将end指针指向这个位置,并将这个位置赋值为'\0'结束符,然后又将end指向下一个位置就是分隔符的下一位,再将s的内容修改为这个地址,所以这个时候sbegin还是传入的指针的指针地址,也就是这一次取到的分段字符串首地址。

调用着调用my_strsep返回的就是这个分段的首地址,同时调用这个函数的过程中修改了字符指针str所指向的位置,它指向了下一个分段的首地址。

strtok、strtok_r 、strsep函数的问题相关推荐

  1. c语言strsep,C/C++ 字符串分割: strtok 与 strsep 函数说明(示例代码)

    函数原型: char *strtok(char *s, const char *delim); char *strsep(char **s, const char *delim); 功能:strtok ...

  2. strtok和strsep函数详解

    函数原型:char *strtok(char *s, const char *delim); char *strsep(char **s, const char *delim); 功能:strtok和 ...

  3. 字符串分割函数strtok和strsep使用注意事项

    转载自 https://blog.csdn.net/astrotycoon/article/details/50813959 为什么写本文 最近工作中经常需要解析字符串,并且这些字符串都有一个共同的特 ...

  4. 探索C语言之字符串分割函数:strtok和strsep的区别

    探索C语言之字符串分割函数:strtok和strsep的区别 概述 strsep - extract token from string(linux 下) strtok, strtok_r - ext ...

  5. 字符串分割函数--strtok与strsep

    在c/c++中,字符串分割函数主要有两种:一是strtok函数,另一个就是strsep函数.下面我们对这两个函数作一个详细解释说明. 1.strtok 原形: char* strtok(char *s ...

  6. strtok strtok_s strsep

    c 语言下的字符串分割函数: 一.strtok(): 原型:char *strtok(char s[], const char *delim); 分解字符串为一组字符串.s为要分解的字符串,delim ...

  7. strsep()函数:字符串切割

    用来分解字符串为一组字符串 1,头文件: #include <string.h> 2,函数原型: char *strsep(char **s, const char *delim); 3, ...

  8. 字符串分割 strsep 函数

    原型:char *strsep(char **stringp, const char *delim); 功能:分解字符串为一组字符串.从stringp指向的位置起向后扫描,遇到delim指向的字符串中 ...

  9. C语言 strsep函数实现

    strsep()函数属于字符串处理函数,作用是使用关键字符(可以是一个,也可以是一个字符串)在一块完整的字符串内存中递增顺序查找,如果在这块字符串内存中查找到关键字符其中的一个那么在当前字符串的位置设 ...

最新文章

  1. 互联网大厂技术面试内幕@霞落满天
  2. PHP中如何给日期加上一个月 加一周 加一天
  3. css3宽度变大动画_动画演示流量计的工作原理
  4. LeetCode 606. Construct String from Binary Tree
  5. selinum-操作表单元素-0223
  6. Kaggle新上比赛:空客公司卫星图像船体分割
  7. 目标检测——知识蒸馏的学习笔记
  8. Good Bye 2016 //智商再次下线,边界爆炸.....
  9. 复合页( Compound Page )
  10. 自学硬件真的可行吗?单片机原理知识点之存储器结构的理解(1)
  11. 第七十三节,css盒模型
  12. 一个站长要具备什么条件?
  13. 开源项目smartImageView
  14. python生成手写汉字字体_「zi2zi」:用AI生成自己的手写字体
  15. C语言中取值符(*)与取地址符()
  16. iPhone已停用,请连接iTunes
  17. HTML让背景图片铺满整个图片
  18. python爬虫项目-优美图库
  19. python绝技运用python成为顶级pdf_python绝技运用Python成为顶级黑客PDF高清文档免费下载...
  20. c补week1(linux c基本操作及C语言部分基础知识)

热门文章

  1. 查询网站的域名注册信息和备案信息
  2. mac:brew无法访问raw.githubusercontent.com解决方式
  3. R语言:多重for循环的加速问题
  4. 自由软件是“绿林好汉”吗?
  5. 微信停止为苹果服务器,艰难选择!微信和支付宝如果停止在苹果手机上使用,会选择谁?...
  6. 极坐标积分 matlab,matlab有关的极坐标与球面坐标计算三重积分0.ppt
  7. Python基础小练习_分支和循环3
  8. 百尺竿头更进一步丨拓展 Amazon Aurora的读写能力之Gaea篇
  9. Activiti工作流并行网关驳回在发起问题
  10. Mac环境配置好ant后提示Permission denied