strtok 函数

strtok 函数C库函数-strtok()C标准库-<string.h>描述C库函数char*strtok(char*str,constchar*delim)分解字符串str为一组字符串,delim为分隔符。声明下面是strtok()函数的声明。char*strtok(char*str,constchar*delim)…

大家好,又见面了,我是你们的朋友全栈君。

 

C 库函数 – strtok()

C 标准库 – <string.h>

描述

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

声明

下面是 strtok() 函数的声明。

char *strtok(char *str, const char *delim)

参数

  • str — 要被分解成一组小字符串的字符串。
  • delim — 包含分隔符的 C 字符串。

返回值

该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。

实例

下面的实例演示了 strtok() 函数的用法。

实例

#include <string.h> #include <stdio.h> int main () { char str[80] = “This is – www.runoob.com – website”; const char s[2] = “-“; char *token; /* 获取第一个子字符串 */ token = strtok(str, s); /* 继续获取其他的子字符串 */ while( token != NULL ) { printf( “%s\n”, token ); token = strtok(NULL, s); } return(0); }

让我们编译并运行上面的程序,这将产生以下结果:

This is 
 www.runoob.com 
 website

===================================================

 

strtok()函数的使用以及注意事项

 

一、函数的简介

         函数原型:char *strtok(char *s, char *delim)

         功能:作用于字符串s,以delim中的字符为分界符,将s切分成一个个子串;如果,s为空值NULL,则函数保存的指针SAVE_PTR在下一次调用中将作为起始位置。

         返回值:分隔符匹配到的第一个子串

二、主要内容

        1、函数的作用是分解字符串,所谓分解,即没有生成新串,只是在s所指向的内容首次出现分界符的位置,将分界符修改成了’/0’,故第一次用strtok()返回第一个子串

         2、第一次提取子串完毕之后,继续对源字符串s进行提取,应在其后(第二次,第三次。。。第n次)的调用中将strtok的第一个参数赋为空值NULL(表示函数继续从上   一次调用隐式保存的位置,继续分解字符串;对于前一次次调用来说,第一次调用结束前用一个this指针指向了分界符的下一位

         3、当this指针指向“\0” 时,即没有被分割的子串了,此时则返回NULL

         4、可以把delim理解为分隔符的集合delim中的字符均可以作为分隔符。

         5、strtok在调用的时候,如果起始位置即为分隔符,则忽略了起始位置开始的分隔符

 

三、使用strtok需要注意的有以下几点:

 

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

设源字符串s为 char buffer[INFO_MAX_SZ]=”,Fred male 25,John male 62,Anna female 16″;  过滤字符串delim为 char *delim = ” “,即空格为分界符。

 image

上图的代码会产生这样的结果:

image

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

理解了buffer的变化,就很好解释函数的返回值了。返回值buf为分界符之前的子串(其实这个说法并不确切,详见”3”中对于返回值的详细说明)。注意,由变量的地址可知,buf依然指向源字符串。

 image

分界符delim没有发生变化,就不再截图了。

 

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

 image

第一次调用的结果如前文所述,提取出了”,Fred”。我们还想继续以空格为分界,提取出后面的”male”等。由上图可以看到,第一次之后的调用我们都给strtok的第一个参数传递了空值NULL(表示函数继续从上一次调用隐式保存的位置,继续分解字符串;对于上述的第二次调用来说,第一次调用结束前用一个this指针指向了分界符的下一位,即’m’所在的位置),这样可依次提取出

image ,image 。。。。以此类推。。。。。

至于为什么要赋空值,要么你就记住结论,要么去查strtok的源代码。本文的最后会有一些介绍。

当然也有部分爱钻牛角尖的人,非不按套路出牌,要看看不赋空值继续赋值为buffer会有什么结果。其实,答案想也能想的到。再一次传递buffer,相当于还从字符串的开头查找分界符delim,而且此时buffer已经被修改(可见的部分只剩下”,Fred”),因此,其结果必然是找不到分界符delim。

 

3.关于函数返回值的探讨

由”1”中所述,在提取到子串的情况下,strtok的返回值(假设返回值赋给了指针buf)是提取出的子串的指针。这个指针指向的是子串在源字符串中的起始位置。子串末尾的下一个字符在提取前为分隔符,提取后被修改成了’/0’。因此,若打印buf的值,可以成功的输出子串的内容。

在没有提取到子串的情况下,函数会返回什么值呢?

 image

由上图可以看到buffer中并不包含分界符delim。调用strtok后buf的值为

 image

因为没有找到,源字符串buffer没有发生改变,buf指向源字符串的首地址,打印输出的值为整个字符串的完整值。

什么时候函数的返回值为空值NULL呢?

百度百科上说,“当没有被分割的串时则返回NULL。”这是一个很模棱两可的说法。如果想要确切的了解清楚这个问题,可能需要看一下strtok的实现原理。这里先以实验说明。

 image

第一次调用strtok,毫无疑问,buf指向”,Fred”。

第二次调用strtok,由于第一个参数为NULL,表示函数继续以上次调用所保存的this指针的位置开始分解,即对”male 25”分解。分解完毕后,buf指向”male”。

第三次调用strtok,参数继续设定为NULL,此时即对第二次保存的this指针的位置开始分解,即对”25”分解。因为无法找到包含分隔符delim的子串,所以buf指向”25”。

image

第四次调用,参数仍为NULL,此时第三次调用保存的this指针已指向字符串的末尾’/0’,已无法再进行分解。因此函数返回NULL,这也就是百度百科中所提到的“当没有被分割的串时函数返回NULL。”

image

 

4.参数 分隔符delim的探讨(delim是分隔符的集合)

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

image

源字符串为buffer,分隔符delim为 逗号和空格,按照一般的想法我们会以为调用函数后,buf的值为”Fred,male,25”,结果是这样么?

image

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

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

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

 

 

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

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

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

image

如上图例子所示。仅用一次调用就可以得到以逗号分隔的字符串”Fred male 25”,而F前面的’,’被忽略了。由此可见,strtok在调用的时候忽略了起始位置开始的分隔符。这一点,可以从strtok的源代码得到证实。

 

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

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

image

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159007.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 挖矿区块链_传说中的区块链挖矿是什么?「建议收藏」

    挖矿区块链_传说中的区块链挖矿是什么?「建议收藏」对于区块链来说,挖矿是必须的吗?首先,我们来说下挖矿是什么?以比特币为例,每一笔交易发生后,并不算完成,交易数据必须写入数据库,才算成立,对方才能真正收到钱。首先,所有的交易数据都会传送到矿工那里。矿工负责把这些交易写入区块链。计算哈希的过程叫挖矿,计算哈希的机器就叫做矿机,操作矿机的人就叫做矿工。根据比特币协议,一个区块的大小最大是1MB,而一笔交易大概是500字节左右,因此一个区块最多可以包…

    2022年5月8日
    40
  • 数组和集合的区别有哪些?

    数组和集合的区别有哪些?更多免费教学文章请关注这里一 数组数组是 java 语言内置的数据类型 他是一个线性的序列 所有可以快速访问其他的元素 数组和其他语言不同 当你创建了一个数组时 他的容量是不变的 而且在生命周期也是不能改变的 还有 JAVA 数组会做边界检查 如果发现有越界现象 会报 RuntimeExcep 异常错误 当然检查边界会以效率为代价 二 集合 JAVA 还提供其他集合 list map set 他们

    2025年7月8日
    4
  • TP传输的两种模式

    TP传输的两种模式

    2021年9月23日
    43
  • 操作系统实验一进程调度算法模拟_常用的进程调度算法有

    操作系统实验一进程调度算法模拟_常用的进程调度算法有今日闲来无聊,发现很早之前写的操作系统实验还没有整理,再加上有很多人问,索性就发成博客吧。实验一进程调度算法一、实验目的  用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解.二、实验指导设计一个有N个进程共行的进程调度程序。  进程调度算法:分别采用先来先服务算法、短作业优先算法、高响应比优先算法实现。  每个进程用一个进程控制块(PCB)表示。…

    2022年9月1日
    6
  • HDU 6138 Fleet of the Eternal Throne ( AC自动机)

    HDU 6138 Fleet of the Eternal Throne ( AC自动机)FleetoftheEternalThroneTimeLimit:2000/1000MS(Java/Others)    MemoryLimit:65536/65536K(Java/Others)TotalSubmission(s):291    AcceptedSubmission(s):131ProblemDescription

    2022年5月31日
    33
  • 渝粤锂电一体机800A_渝粤锂电池怎么样

    渝粤锂电一体机800A_渝粤锂电池怎么样选择题题目:英国经济学家罗宾斯的著名论文《轮经济科学的性质和意义》发表于()题目:亚当˙斯密的《国富论》发表于()题目:西方经济学产生的根本原因是()题目:西方主流经济学家主要采用下列哪种方法论来进行经济学研究()题目:微观行为与宏观结果甚至可能是背离的。对此,萨缪尔森在他经典的教科书上曾打过一个精辟的比方。他说,好比在一个电影院看电影,有人被前面的人挡住了视线,如果他站起来的话,他看电影的效果将会改善。因此,站起来就微观而言是合理的。但是,如果大家都站起来的话,则大家看电影的效果都不能

    2025年8月13日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号