strtok函数缺陷再探

简介:     要将类似“a a a,b b b,c c c,d d d,e e e,f f f”这样的字符串一一分割出来,如何实现? 1、使用strtok()存在的缺陷     strtok()函数嵌套使用,无论是在同一个函数中或者在主调和被调函数中同时使用strtok的开始语句如strtok(str,","); 都极易出现问题。

    要将类似“a a a,b b b,c c c,d d d,e e e,f f f”这样的字符串一一分割出来,如何实现?


1、使用strtok()存在的缺陷

    strtok()函数嵌套使用,无论是在同一个函数中或者在主调和被调函数中同时使用strtok的开始语句如strtok(str,","); 都极易出现问题。看下面案例:


  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.     char buffer[] = "a a a,b b b,c c c,d d d,e e e,f f f";
  4.     char *buf = buffer;
  5.     char *p[30];
  6.     int i = 0;
  7.     printf("Before strtok,len of buffer = %d\n",strlen(buffer));

  8.     while((p[i]=strtok(buf,",")) != NULL)
  9.     {
  10.         buf = p[i];
  11.         printf("%s\n",buf);
  12.         while( (p[i]=strtok(buf," ")) != NULL )
  13.         {
  14.             printf("%s\n",p[i]);
  15.             i++;
  16.             buf = NULL;
  17.         }
  18.         printf("========================\n");
  19.         buf = NULL;
  20.     }

  21.     printf("after strtok,len of buffer = %d",strlen(buffer));
  22.     getchar();
  23.     return 0;
  24. }


上面代码的运行效果如下:

image图1

 

    由上面的运行效果可以看出,这个并不是我们想要的效果。因为它只分割了buffer数组第一个逗号前面的字符串。

    很明显,因为内循环中使用了strtok同时也使用了静态指针变量,使得内循环执行结束时,外循环的strtok函数给静态变量所赋的值被修改了;而我们想要的是第一次内循环执行结束时,这个静态变量应该存储的是字符串”b b b,c c c,d d d,e e e,f f f”的首地址。

image 图2 外循环未进行分割前

 

image

图3 外循环进行一次分割

 

image

图4 内循环运行结束

 

    注意,虽然号称为分割,实际上整个buffer的存储空间内初始元素是不变的。分割的实质利用的一个向前移动的分割指针,凡是遇到分割符,就将该置置\0并返回分割符前面的字符串指针,图6证明了这个说法。上面程序中,对buffer执行一次外循环、一次内循环前后的对比结果,见图5:

image图5

 

image

图6


问题:为什么外循环只执行了一次就结束了呢?

    我们假设,strtok需要与一个静态的指针变量一起搭配使用。上面代码所使用使用了两套strtok,而保存地址的指针变量只有一个。当外循环第一次执行时,指针变量存储的是字符’b’所在的地址。而因为下面又执行了内循环,当内循环的strtok执行结束,指针变量此时存储的是”a\0a\0a\0”,第三个’a’的地址。

    当外循环的strtok从第三个’a’地址开始往后遍历时,刚一移动,就遇到了”\0”,没办法。
    所谓出师未捷身先死,就出现本例图1所示的效果了。


 

2、使用strtok_s()函数(linux下是strtok_r())就能实现我们想要的效果


  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3.     char buffer[] = "a a a,b b b,c c c,d d d,e e e,f f f";
  4.     char *buf = buffer;
  5.     char *p[30];
  6.     int i = 0;
  7.     char *outer_ptr = NULL;
  8.     char *inner_ptr = NULL;
  9.     printf("Before strtok,len of buffer = %d\n",strlen(buffer));

  10.     while((p[i]=strtok_s(buf,",",&outer_ptr)) != NULL)
  11.     {
  12.         buf = p[i];
  13.         printf("%s\n",buf);
  14.         while( (p[i]=strtok_s(buf," ",&inner_ptr)) != NULL )
  15.         {
  16.             printf("%s\n",p[i]);
  17.             i++;
  18.             buf = NULL;
  19.         }
  20.         printf("========================\n");
  21.         buf = NULL;
  22.     }

  23.     printf("after strtok,len of buffer = %d",strlen(buffer));
  24.     getchar();
  25.     return 0;
  26. }


image图7

 

strtok_s()函数是如何实现这个功能的呢?这又如何解释呢?

image

图8

    由图8,因为每个strtok各自维护一个pointer,所以无论进行分割后进行什么操作,这些pointer都会很忠实的记住下一次开始的地址。从而避免出现1中的由于strtok嵌套使用引入的问题。

 

 

参考博客:

http://www.cnblogs.com/hoys/archive/2011/09/19/2180999.html

PS: 参考博客的博主hoy同时也是在下的老友,向hoy的探索和贡献精神致敬!

相关文章
|
Unix Linux Shell
patch 命令用法详解(转)
patch,是打补丁的命令,有很多用法,见帮助#man patch patch -p0       (“p”指的是路径,后面的数字表示去掉路径的第几部分。"0",表示不去掉,为全路径) patch -p1       (“p”后面的数字"1",表示去掉前第一个路径) fetch http://people.
11128 0
|
Linux 网络安全 Python
linux centos上安装python3.11.x详细完整教程
这篇文章提供了在CentOS系统上安装Python 3.11.x版本的详细步骤,包括下载、解压、安装依赖、编译配置、解决常见错误以及版本验证。
11480 3
linux centos上安装python3.11.x详细完整教程
|
运维 Cloud Native 持续交付
云原生架构的演进与实践####
【10月更文挑战第16天】 云原生,这一概念自提出以来,便以其独特的魅力和无限的可能性,引领着现代软件开发与部署的新浪潮。本文旨在探讨云原生架构的核心理念、关键技术及其在实际项目中的应用实践,揭示其如何帮助企业实现更高效、更灵活、更可靠的IT系统构建与管理。通过深入剖析容器化、微服务、持续集成/持续部署(CI/CD)等核心技术,结合具体案例,本文将展现云原生架构如何赋能企业数字化转型,推动业务创新与发展。 ####
398 47
|
10月前
|
人工智能 搜索推荐 算法
PDF 转 JPG 图片小工具:CodeBuddy 助力解决转换痛点
在 PDF 转 JPG 的实际应用中,用户普遍面临转换质量差、批量处理效率低、格式兼容性不足以及编程实现困难等痛点。而 CodeBuddy 凭借智能代码生成与优化、实时错误诊断修复、助力代码学习拓展,以及支持多场景适配与个性化定制等强大的 AI 编程能力,精准直击这些难题。使用 CodeBuddy 开发 Python PDF 转 JPG 小工具,能够有效提升转换效率与质量,降低开发门槛和成本,为用户带来高效、优质的文件格式转换体验。
360 16
|
10月前
|
监控 搜索推荐 UED
301重定向对SEO的影响:全面解析与最佳实践
本文深入探讨了301重定向在SEO中的作用,涵盖基本概念、积极影响(如保留链接权重、避免重复内容)、潜在风险(如权重传递不完全、错误实施)及最佳实践。同时对比了其他重定向类型,提供了技术实现建议和常见应用场景,帮助网站管理员正确使用301重定向以优化用户体验和搜索引擎表现。
493 16
|
存储 算法 数据处理
Pandas高级数据处理:数据压缩与解压
本文介绍 Pandas 中的数据压缩与解压技术,探讨其在大数据集存储、远程传输和备份归档中的应用场景。Pandas 支持多种压缩格式(如 `.gzip`、`.bz2`、`.zip`),通过 `compression` 参数轻松实现数据的压缩与解压。文中还提供了常见问题的解决方案,如文件扩展名不匹配、内存不足和性能优化,并介绍了自动检测压缩格式和组合压缩加密的高级技巧。掌握这些功能可显著提升数据处理效率。
383 20
|
Shell Windows
电脑文件打开缓慢、右键卡顿解决方案
本文汇总了几种解决电脑文件打开缓慢和右键点击文件夹卡顿问题的方案,包括重启资源管理器、修改注册表中的Shell Extensions、以及设置在单独的进程中打开文件夹窗口。
|
传感器 存储 安全
智能标签:物品追踪与管理的革新
【10月更文挑战第19天】智能标签技术通过集成RFID、二维码和传感器等技术,实现了物品的高效追踪与管理,广泛应用于物流、零售、医疗、交通和工业等领域,正引领物品管理的革新。本文探讨其原理、技术、应用及未来趋势。
|
监控 开发者 UED
QLineEdit:textChanged、textedited区别
总之,理解 `textChanged`与 `textEdited`之间的细微差别,可以帮助开发者更加精准地控制用户界面的响应逻辑,提升应用程序的互动性和效率。
668 3
|
图形学 Android开发 开发者
U3D游戏开发实战:有效策略缩小包体大小,提升加载速度
【7月更文第12天】随着移动设备的普及,Unity 3D(简称U3D)作为一款强大的跨平台游戏开发引擎,成为了众多独立开发者和游戏工作室的首选。然而,面对日益增长的用户需求与有限的设备存储空间,如何在保证游戏质量的同时,有效缩减游戏包体大小,成为了开发者面临的一大挑战。本文将探讨一系列实用技巧和最佳实践,帮助你在U3D开发小游戏时显著减小包体尺寸,从而提升玩家的下载体验与启动速度。
599 12