c/cpp中如何分割字符串,类似于split的功能

在python中,如果要求当前时间的unix时间戳,我特别喜欢这么用:

import time
timestr = time.time()
timestamp = int(timestr.split('.')[0])

这里的split函数,我非常喜欢,在java、c#和python中都有,很方便,不用担心踩地雷,但是C/CPP中,就没有了,这点比较遗憾。

如果要处理一个字符串型的“192.168.1.254”,想把每个字段都分开,怎么办呢,C标准库中有函数strtok()的实现,可以一用。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

在这里,strtok是非线程安全的,这点也可以在程序的第二次strtok调用中看到,因此linux用strsep来替换strtok了,我在linux2.6.22的源码/lib/string.c和linux-3.3中同文件中,c文件开头就是这样一段话:

/*
 *  linux/lib/string.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/*
 * stupid library routines.. The optimized versions should generally be found
 * as inline code in <asm-xx/string.h>
 *
 * These are buggy as well..
 *
 * * Fri Jun 25 1999, Ingo Oeser <[email protected]>
 * -  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 <[email protected]>,
 *                    Matthew Hawkins <[email protected]>
 * -  Kissed strtok() goodbye
 */

因为strsep是线程安全的,并且速度上更快一些,所以采用strsep来替换strtok,接下来我会试一试strsep。在这里感慨下,没事的时候或者写程序的时候,用man和查看源码的方式,能学到很多基本的知识,比如内核源码的lib文件夹下,linux内核使用的rbtree结构,还有lib文件夹的string.c,include下的string.h里的各种strcpy,strcat等基本函数的实现,都是非常经典而且久经考验的。

在strtok使用的代码里,有两处很有意思。

其中一个,修改第7行,如下所示:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char *ip_str = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

将char ip_str[] = "192.168.1.250";改为char *ip_str = "192.168.1.250";就会core dump,通过gdb和core文件来看,程序崩溃在了

Program terminated with signal 11, Segmentation fault.
#0  strtok () at ../sysdeps/i386/i686/strtok.S:245
245 	 movb $0, (%edx) /* Terminate string.  */
(gdb) where
#0  strtok () at ../sysdeps/i386/i686/strtok.S:245
#1  0x0804841e in main () at test.c:9

而这段代码在VS下是没有问题的,所以这个原因需要找一下。

这个原因找到了,在链接http://www.cnblogs.com/longzhao1234/archive/2012/05/31/2528317.html

通过阅读源代码,因为函数内部会修改原字符串变量,所以传入的参数不能是不可变字符串(即文字常量区)。

如 char *tokenremain ="abcdefghij"//编译时为文字常量,不可修改。

strtok(tokenremain,"cde");

strsep(&tokenremain,"cde");

编译通过,运行时会报段错误。

VS在很多情况下要比GCC优秀很多,VS的CPP支持是最全面的,可以这么说。好多CPP的作者啦,大牛啦,都是M$的VC组的,好牛逼的地方。

另外在改一处,这次只改第16行,将printf语句注释掉,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

又崩溃了,我也整个人都不好了。

分析core文件,出错如下:

Program terminated with signal 11, Segmentation fault.
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99
99 	 movl (%eax), %ecx /* get word (= 4 bytes) in question */
(gdb) where
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99
#1  0x00b9ddd5 in _IO_puts (str=0x0) at ioputs.c:37
#2  0x0804846b in main () at test.c:16

令人欣慰的是,VS在这句也崩了。

根据core文件的提示,在#0处,在strlen函数这里崩溃了,我判断,是strtok阶段字符数组到最后,要在printf("%s\n",s);处打印时,由于没有‘\0‘符号,所以缓冲区无法截断,最后溢出导致printf崩溃,所以我重新声明一个长度为sizeof(ip_str)+1的字符数组,将ip_str复制进去,并将最后一个字符置为‘\0‘,代表字符结束,结果依然崩溃。

如果我把printf("%s\n",s);改为printf("%s\t",s);,因为printf是打印到标准输出中,而标准输出是行缓冲的,对于‘\n‘,代表行缓冲结束,需要输出,如果我不让他输出,会怎样?

打印结果为:

168	1	250	(null)	

好吧我也不知道是什么了,而且这个结果与是否有‘\0‘符号无关。

这两个地方一定要找出来问题,嗯。

接下来我们看看strsep的用法吧

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *p = ip_str;
	char *ip_arr[4] ;
	char * s = strsep(&p, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strsep(&p, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

用法也差不多。

c/cpp中如何分割字符串,类似于split的功能

时间: 2024-07-30 23:53:24

c/cpp中如何分割字符串,类似于split的功能的相关文章

Delphi中stringlist分割字符串的用法

Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaText 2.Delimiter &DelimitedText 3.Names &Values &ValueFromIndex 先看第一个:CommaText.怎么用呢? const constr :String = 'aaa,bbb,ccc,ddd'; var strs :TStrin

c/cpp中怎样切割字符串,相似于split的功能

在python中,假设要求当前时间的unix时间戳,我特别喜欢这么用: import time timestr = time.time() timestamp = int(timestr.split('.')[0]) 这里的split函数,我非常喜欢,在java.c#和python中都有,非常方便,不用操心踩地雷,可是C/CPP中,就没有了,这点比較遗憾. 假设要处理一个字符串型的"192.168.1.254",想把每一个字段都分开,怎么办呢,C标准库中有函数strtok()的实现,能

c++分割字符串(类似于boost::split)

由于c++字符串没有split函数,所以字符串分割单词的时候必须自己手写,也相当于自己实现一个split函数吧! 如果需要根据单一字符分割单词,直接用getline读取就好了,很简单 1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <sstream> 5 using namespace std; 6 7 int main() 8 { 9 string words

sql语句中如何分割字符串进行替换

碰到一个这样的需求,修改父文件夹名称,要全部更新掉子节点的名称. 规则是保留子节点按-分割后的最后一个元素不变,前面的字符串更新为父节点名称. 如下图: 假如我修改父节点 "东南网-西岸时评 测试"-> "东南网测试",则下面的节点应该要这样的结果: 原来处理的sql语句: update websiteB set websiteName=websiteName where [email protected] 显然是无法满足的,用存储过程,涉及到游标遍历,还要再

Mysql中字段分割字符串( 一行转多行 )

t_customers 表中的一条记录: 需要的结果: sql实现 SELECT a.id, a.username, SUBSTRING_INDEX( SUBSTRING_INDEX( a.operid, ';', b.help_topic_id + 1 ), ';',- 1 ) AS ids FROM `t_customers` AS a JOIN mysql.help_topic AS b ON b.help_topic_id < ( length( a.operid ) - length(

python中分割字符串split切割并选择输出 逐行读取文件后字符串拼接

字符串根据分隔符切割后输出,一下面 #!/usr/bin/python # -*- coding: utf-8 -*- str="abc,123 efg,567" #以空行分割后输出 print str.split(); #以','分割2次后输出 print str.split(',',2); #以','分割2次后输出地2个参数,1是从0开始,代表第二个参数 print str.split(',',2)[1]; 输出结果如下: ['abc,123', 'efg,567'] ['abc'

javascript 中 split 函数分割字符串成数组

分割字符串成数组的方法有很多,不过使用最多的还是split函数 <script language="javascript"> str="2,2,3,5,6,6"; //这是一字符串 var strs= new Array(); //定义一数组 strs=str.split(","); //字符分割 for (i=0;i<strs.length ;i++ ) { document.write(strs[i]+"<b

模拟java的split函数,分割字符串,类似于java的split方法

/*自定义oracle的分割函数*//*定义一个type,用户接收返回的数据集合*/create or replace type splitType as table of varchar2(4000); /* 参数1: 被分割的字符串 参数2:分割字符串,默认是英文逗号*/create or replace function split_str(str varchar2, split_char varchar2:=',') return splitType pipelinedis idx nu

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能)

Delphi中怎样将字符串按给定字符分隔(类似split函数的功能) 分类:            Delphi2007-05-16 11:094911人阅读评论(2)收藏举报 delphiintegerstringbutton文本编辑function 今天偶尔要做的Delphi程序,其中涉及到了字符串处理,里面有一个功能类似于VB里的split()函数的功能,于是查了很久才查到些资料,现将这些资料整理一下,方便大家. 首先是一个网友自己编的函数.实现了和split()函数的功能. unit U