Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65480
  • 博文数量: 20
  • 博客积分: 241
  • 博客等级: 二等列兵
  • 技术积分: 157
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-19 15:34
文章分类
文章存档

2013年(2)

2012年(12)

2011年(6)

分类: C/C++

2011-08-27 14:54:50


c语言里面常用的字符串分割函数有strtok和strsep,两者原型定义及说明如下:

一,strtok函数

1.原型:char *strtok(char *s, const char *delim);


2.功能
:分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。

3.说明:
    strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到 参数delim的分割字符时则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。

4.返回值:
   
从s开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。   所有delim中包含的字符都会被滤掉,并将被滤掉的地方设为一处分割的节点。

5.程序示例:

#include

#include

int main(int argc,char * argv[])
{
char input[16] = "abc,d";
char *p;

p = strtok(input, ",");

if (p)
    printf("%s\n", p);
p = strtok(NULL, ",");

if (p)
    printf("%s\n", p);

return 0;
}

二,strsep函数

1.原型:char *strsep(char **stringp, const char *delim);

2.功能:
    分解字符串为一组字符串。从stringp指向的位置起向后扫描,遇到delim指向位置的字符后,将此字符替换为NULL,返回stringp指向的地址。

3.程序示例:

示例程序<1>:

#include

int main(int argc,char *argv[])
{
char string[] = "words separated by spaces";
char *running;
char *token;

running=string;
while((token = strsep (&running," "))!=NULL)
printf("%s\n",token);
return 0;
}

示例程序<2>:

#include
#include
#define STR "1:12::34:6"

int main(int argc,char *argv[])
{      
        char test_string[100];

        char *p,*k;
 
       int i;
 
       k = test_string;
 
       strcpy(test_string,STR);

        printf("orgin: %s\n",test_string);
 
       for(i=0;i<5;i++){
 
               p = strsep(&k,":");
 
               printf("%s\n",p);
 
       }
 
       printf("after:%s\n",test_string);

        return 0;

}

执行结果显示:

orgin: 1:12::34:6
1
12

34
6
after:1

结论:

该函数貌似会破坏原来的字符串!!!

--------------------------------------------------------------------------------------------------------------
如上是应用层程序所使用的字符串分割函数,与此同时,在linux内核中也宣判了strtok函数的死亡。

注:摘自Linux内核2.6.29,说明了这个函数已经不再使用,由速度更快的strsep代替。
  /*
  * linux/lib/string.c
  *
  * Copyright (C) 1991, 1992 Linus Torvalds
  */
  /*
  * stupid library routines.. The optimized versions should generally be found
  * as inline code in
  *
  * These are buggy as well..
  *
  * * Fri Jun 25 1999, Ingo Oeser
  * - 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 ,
  * Matthew Hawkins
  * - Kissed strtok() goodbye
  */
--------------------------------------------------------------------------------------------------------------
转l很早有关使用strsep函数使用讨论!

问题标题:为何strsep只能够操作堆中的字符串呢?

#include
#include

struct item {
         
char name[32];
          char *value;
          struct item *next;
};

int main(int argc,char *argv[])
 {
char *channel,*start,*end;
struct item test;

snprintf(test.name,31,"%s", "channel");

test.value = (char *)malloc(128);

snprintf(test.value,127,"%s","1-15,17-31,43,55");
if(!strcasecmp(test.name,"channel"))
{
     while(channel = strsep(&test.value,","))
      {
            start = strsep(&channel,"-");
            if(channel)
           {
                end = channel;
                printf("include channel start from %s to %s\n",start,end);
            }
           else
                printf("include channel %s\n",start);
     }
}
return 0;

}

[root@localhost program]# ./strsep
include channel start from 1 to 15
include channel start from 17 to 31
include channel 43
include channel 55
--------------------------------------------------------------------------------------------------------------
#include
#include

struct item {

char name[32];
char value[128];
struct item *next;
};

 int main(
int argc,char *argv[])
{
char *channel,*start,*end;
struct item test;
snprintf(test.name,31,"%s", "channel");
//test.value = (char *)malloc(128);

snprintf(test.value,127,"%s","1-15,17-31,43,55");
          if(!strcasecmp(test.name,"channel"))
          {
              
while(channel = strsep(&test.value,","))
               {
                    start = strsep(&channel,"-");
         
                    if(channel)
                    {
                         end = channel;
                         printf("include channel start from %s to %s\n",start,end);

                    }
          
        else
                         printf("include channel %s\n",start);
                 }
            }

            return 0;
}

[root@localhost program]# ./strsep Segmentation fault
--------------------------------------------------------------------------------------------------------
修改后无问题源码:

#include
#include

struct item {
char name[32];
char value[128];
struct item *next;
};

int main(int argc,char *argv[])
{
      char *channel,*start,*end,*p;
      struct item test;
      snprintf(test.name,31,"%s", "channel");
      //test.value = (char *)malloc(128);
      snprintf(test.value,127,"%s","1-15,17-31,43,55");
     
       if(!strcasecmp(test.name,"channel"))
       {
              p = test.value;

              while(channel = strsep(&p,","))
              {
                       start = strsep(&channel,"-");
                    
                       if(channel)
                        {
                               end = channel;
                               printf("include channel start from %s to %s\n",start,end);
                       
}
                        else
                               printf("include channel %s\n",start);

               }
}
return 0;
}
--------------------------------------------------------------------------------------------------------

(1)
多谢各位,不过我一直都没有注意过char ** 和char *[]的区别,因为总是看到 int main(int argc, char *argv[]) 和int main(int argc, char **argv)这两种写法,似乎都把这两种类型当着一样的而没有区分。去看看这两个究竟有什么区别!
(2)看了一圈,大致明白char ** 和char *[]的区别了,确切的说在strsep里是因为char * 和char []这两者的区别引起的。char *纯粹是一个指针,它指向的地方可以更改,而char []虽然平时把它和char *同等对待,但是它所指向的地方却不能更改。
--------------------------------------------------------------------------------------------------------

阅读(7194) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

starscloudcsl2014-10-25 18:36:20

大哥,我比较关注哪个错误案例是如何编译通过的。

将&test.value传递给 char **p 是怎么通过编译的呀?