• 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]);
    }

    使用方法也差点儿相同。

  • 相关阅读:
    移动开发 Native APP、Hybrid APP和Web APP介绍
    urllib与urllib2的学习总结(python2.7.X)
    fiddler及postman讲解
    接口测试基础
    UiAutomator2.0 和1.x 的区别
    adb shell am instrument 命令详解
    GT问题记录
    HDU 2492 Ping pong (树状数组)
    CF 567C Geometric Progression
    CF 545E Paths and Trees
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4254076.html
Copyright © 2020-2023  润新知