今天遇到了处理字符串的问题,比如分割问题,但是一时间想不起来什么方法,也不想手写一个类似java String中的split函数,于是百度了一下,发现了strtok这个好用的方法,以此作为总结。

strtok函数的使用是一个老生常谈的问题了。该函数的作用很大,争议也很大。以下的表述

使用的源代码大部分来自于网络,我稍加修改作为例证。当然,本人水平有限,有不妥之处望各位多多指教。

strtok 的函数原型为char *strtok(char *s, char *delim),功能为“Parse S into tokens separated by characters in DELIM.If S is NULL, the saved pointer in SAVE_PTR is used as the next starting point. ” 翻译成汉语就是:作用于字符串s,以包含在delim中的字符为分界符,将s切分成一个个子串;如果,s为空值NULL,则函数保存的指针 SAVE_PTR在下一次调用中将作为起始位置。

函数的返回值为从指向被分割的子串的指针。

要点纪要:

1.函数的作用是分解字符串,所谓分解,即没有生成新串,只是在str所指向的内容上做了些手脚而已。因此,源字符串str发生了变化!

下面就以str[] = "ab,c,d"为简单案例一代吗来证实其str发生了变化:

#include <string.h>
#include <stdio.h> int main(void)
{
char str[] = "ab,c,d";
char *p = NULL;
char *delim = ","; int in = 0;
p = strtok(str, delim);
while(p != NULL){
printf("the character is :%s\n",p);
printf("the str is : %s\n",str);
p = strtok(NULL,delim);
}
}

代码执行后输出结果:

the character is :ab
the str is : ab
the character is :c
the str is : ab
the character is :d
the str is : ab

有上面的结果可知,str发生了变化。 此时打印str的值,只会显示“ab”,而后面" ,c,d”不翼而飞了。实际上,strtok函数根据delim中的分界符,找到其首次出现的位置,即ab后面那个空格(str[2]),将其修改成了 '\0’。其余位置不变。这就很好解释为什么打印str的值只能出现“ab”,而非str中的全部内容了。因此,使用strtok时一定要慎重,以防止源字符串被修改。

理解了str的变化,就很好解释函数的返回值了。返回值delim为分界符之前的子串;由变量的地址可知,p依然指向源字符串。

2.若要在第一次提取子串完毕之后,继续对源字符串s进行提取,应在其后(第二次,第三次。。。第n次)的调用中将strtok的第一个参数赋为空值NULL。

第一次之后的调用我们都给strtok的第一个参数传递了空值NULL(表示函数继续从上一次调用隐式保存的位置,继续分解字符串;对于上述的第二次调用来说,第一次调用结束前用一个this指针指向了分界符的下一位,即'c’所在的位置), 这样可依次提取出 "c d",加入你感觉为什么非要赋空值,我如果不赋空继续赋值为str会有什么结果。其实,答案想也能想的到。再一次传递str,相当于还从字符串的开头查找分界符delim,而且此时str已经被修改(可见的部分只剩下"ab"),因此,其结果必然是找不到分界符delim只是打印出ab后面的就没有办法打 印出来了。

3.分隔符delim的探讨(delim是分隔符的集合)

多人在使用strtok的时候,都想当然的以为函数在分割字符串时完整匹配分隔符delim,比如delim=”ab”,则对于"acdeab”这个字符
串,函数提取出的是"acde”。至少我在第一次使用的时候也是这么认为的。其实我们都错了,我是在看函数的源代码时才发现这个问题的,且看下面的例子。

int main(void)
{
char str[] = "acdeab";
char *p = NULL;
int in = 0;
p = strtok(str, "ab");
while(p != NULL){
printf("the character is :%s\n",p);
p = strtok(NULL,"ab");
}
}

输出的结果为:

 the character is :cde

第一次调用之后的结果竟然是"cde”,而非我们所想的结果。这是为什么呢?

我们回到GNU C Library中对strtok的功能定义:“Parse S into tokens separated by characters in DELIM”。也就是说包含在delim中的字符均可以作为分隔符,而非严格匹配。可以把delim理解为分隔符的集合。这一点是非常重要的。

当然,我们在分解字符串的时候,很少使用多个分隔符。这也导致,很多人在写例子的时候只讨论了一个分隔符的情况。有更多的人在看例子的时候也就错误的认识了delim的作用。

4.待分解的字符串,首字符就为分隔符

首字符为分隔符不能算作一个很特殊的情况。按照常规的分解思路也能正确分解字符串。

由此说明的是,strtok对于这种情况采用了比常规处理更快的方式。

仅用一次调用就可以得到以“ab”分隔的字符串"acdeab”,而前面的a被忽略了。由此可见,strtok在调用的时候忽略了起始位置开始的分隔符。这一点,可以从strtok的源代码得到证实。

5.不能向第一个参数传递字符串常量!

本文中所举的例子都将源字符串保存为字符串数组变量。若你将源字符串定义成字符串常量,可想而知,程序会因为strtok函数试图修改源字符串的值,而抛出异常Segementation fault。

对于该函数的使用我也就理解到这里,如果还有其他的用法以后发现再来完善吧。

转自:http://blog.chinaunix.net/uid-25940216-id-3137640.html

(转载)关于Linux C函数strtok的使用要点的更多相关文章

  1. 关于函数strtok和strtok_r的使用要点和实现原理(二)【转】

    本文转载自:http://astute11.blog.51cto.com/4404646/1334199 (一)中已经介绍了使用strtok函数的一些注意事项,本篇将介绍strtok的一个应用并引出s ...

  2. 字符串分割函数 STRTOK & STRTOK_R (转)

    1.一个应用实例 网络上一个比较经典的例子是将字符串切分,存入结构体中.如,现有结构体 typedef struct person{     char name[25];     char sex[1 ...

  3. 关于函数strtok和strtok_r的使用要点和实现原理(二)

    http://www.cnblogs.com/stemon/p/4013264.html已经介绍了使用strtok函数的一些注意事项,本篇将介绍strtok的一个应用并引出strtok_r函数. 1. ...

  4. linux常用函数简单介绍

    mmap函数简介: mmap函数是unix/linux下的系统调用,来看<Unix Netword programming>卷二12.2节对mmap的介绍: The mmap functi ...

  5. 关于函数strtok和strtok_r的使用要点和实现原理

    strtok函数的使用是一个老生常谈的问题了.该函数的作用很大,争议也很大.以下的表述可能与一些资料有区别或者说与你原来的认识有差异,因此,我尽量以实验为证.交代一下实验环境是必要的,winxp+vc ...

  6. 动态替换Linux核心函数的原理和实现

    转载:https://www.ibm.com/developerworks/cn/linux/l-knldebug/ 动态替换Linux核心函数的原理和实现 在调试Linux核心模块时,有时需要能够实 ...

  7. linux 系统函数之 (dirname, basename)【转】

    转自:http://blog.csdn.net/peter_cloud/article/details/9308333 版权声明:本文为博主原创文章,未经博主允许不得转载. 除非你的原件考虑跨平台. ...

  8. linux C函数之strdup函数分析【转】

    本文转载自:http://blog.csdn.net/tigerjibo/article/details/12784823 linux C函数之strdup函数分析 一.函数分析 1.函数原型: #i ...

  9. Linux open函数

    Linux open函数 open 函数用于打开和创建文件.以下是 open 函数的简单描述 #include <fcntl.h> int open(const char *pathnam ...

随机推荐

  1. python工作中总结

    以下方法平时很少用,用其它解决方法,只是总结了一些其它同事的技巧 1   如何自动生成列表,加一个条件还能筛选 [x for x in range(10) if x>5 ] 来生一个字典试试 d ...

  2. 从输入 URL 到展现页面的全过程

    总体分为以下几个过程 DNS解析 TCP连接 发送HTTP请求 服务器处理请求并返回HTTP报文 浏览器解析渲染页面 连接结束 DNS解析 域名到ip地址转换 TCP连接 HTTP连接是基于TCP连接 ...

  3. python循环以及控制语句

    python流程 学习完本篇,你将会通过python完成以下题目 试利用break语句求解2-100之间的素数. (1)素数是指除了能被1和它本身整除外,不能被其它数所整除的数.判断一个自然数是否是素 ...

  4. vscode中tab键无法触发emmet

    在用户自定义处加上一个设置"emmet.triggerExpansionOnTab":true

  5. Jmeter系列(6)- 分析源码,创建登录、浏览商品接口请求

    前言简介 接口的压力测试有个二八原则:线上80%的用户量在一天24小时20%(即4.8个小时)的时间里可以平稳运行,这个接口就算是通过压力测试了 源码分析 登录 浏览商品 创建请求 登录 浏览菜单 C ...

  6. LateX出坑

    1 公式是用$ 包围着的  $ 2 \begin{equation} 里面的公式自动编号   \end{equation} 要达成这样的效果,暂时想到如下方法: 1 \begin{equation} ...

  7. WPF进阶技巧和实战03-控件(5-列表、树、网格04)

    ListView控件 ListView继承自简单的没有特色的ListBox,增加了对基于列显示的支持,并增加了快速切换视图或显示模式的能力,而不需要重新绑定数据以重新构建列表. ListView类继承 ...

  8. 国庆出游神器:魔幻黑科技换天造物,让vlog秒变科幻大片!

    摘要:国庆旅游景点人太多,拍出来的照片全是人人人.车车车,该怎么办?不妨试试这个黑科技,让你的出游vlog秒变科幻大片. 本文分享自华为云社区<国庆出游神器,魔幻黑科技换天造物,让vlog秒变科 ...

  9. spring-data-redis 上百万的 QPS 压力太大连接失败,我 TM 人傻了

    大家好,我们最近业务量暴涨,导致我最近一直 TM 人傻了.前几天晚上,发现由于业务压力激增,某个核心微服务新扩容起来的几个实例,在不同程度上,出现了 Redis 连接失败的异常: org.spring ...

  10. 为什么'\x1B'.length===1?\x与\u知识延伸

    背景 先讲一下背景,再说原因 大多数库都会在日志中使用chalk库为console的内容进行上色 被chalk处理后,其原本的内容会被'\x1B...'所包裹 console.log(chalk.bl ...