• 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
    ",s);
    	}
    
    	for(i=0; i<4; i++)
    		printf("%s
    ",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 <ioe@informatik.tu-chemnitz.de>
     * -  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 <jason@topic.com.au>,
     *                    Matthew Hawkins <matt@mh.dropbear.id.au>
     * -  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
    ",s);
    	}
    
    	for(i=0; i<4; i++)
    		printf("%s
    ",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
    ",s);
    	}
    
    	for(i=0; i<4; i++)
    		printf("%s
    ",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 ",s);处打印时,因为没有''符号,所以缓冲区无法截断,最后溢出导致printf崩溃,所以我又一次声明一个长度为sizeof(ip_str)+1的字符数组,将ip_str复制进去,并将最后一个字符置为'',代表字符结束,结果依旧崩溃。

    假设我把printf("%s ",s);改为printf("%s ",s);,由于printf是打印到标准输出中,而标准输出是行缓冲的,对于' ',代表行缓冲结束,须要输出,假设我不让他输出,会如何?

    打印结果为:

    168	1	250	(null)	
    好吧我也不知道是什么了,并且这个结果与是否有''符号无关。


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


    接下来我们看看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
    ",s);
    	}
    
    	for(i=0; i<4; i++)
    		printf("%s
    ",ip_arr[i]);
    }

    使用方法也差点儿相同。

  • 相关阅读:
    如何为新的应用获取更高的关键字排名
    AppStore审核不通过?看看问题出在哪儿
    django 学习-11 Django模型数据模板呈现
    django 学习-10 Django多对多关系模型
    Django学习--9 Admin
    Django学习--9 多对一关系模型
    django 学习-7 模型数据操作
    django 学习-6 定义模型--数据库的使用
    django 学习-5 模板使用流程
    django 学习-4 模板标签
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4254076.html
Copyright © 2020-2023  润新知