LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1523|回复: 19

再议从buffer中提取word

[复制链接]
发表于 2003-10-15 08:23:37 | 显示全部楼层 |阅读模式
兄弟想从一个bufline中提取以特定字符分隔的word,写了以下的程序。
已经编译成功,可以实现了。现在有几个问题想请教一下。

1。不知道会不会由缓冲区溢出的情况。如何改进。
2。执行效率能不能再提高些。有什么好的想法。

我以前写的getword程序,效率高些,但是通用性差,我是用的是安顺序的取word的。

  1. //功能同strchr 在字符串s中查找第n个字符c,成功返回指向第n个字符c的指针,失败返回空指针。
  2. char *strnchr(char *s,int c,int n)
  3. {
  4. char *first;
  5. int i;
  6. if (n <= 0)
  7. {       fprintf(stderr,"arguments n below 0 \n");
  8.         return NULL;
  9. }
  10. if (n == 1)
  11.         return strchr(s,c);
  12. // n => 2
  13. first = strchr(s,c);
  14. for(i = 2;i <= n;i++)
  15. {
  16. first++;
  17. first = strchr(first,c);
  18. if (first == NULL)
  19.         break;
  20. }
  21. return first;
  22. }


  23. // 从linebuf中取出由delim分隔开的第n个word,放入wordbuf中。成功返回指向wordbuf的指针,失败返回NULL。
  24. char *getnword( char *linebuf,char *wordbuf,char delim, int n)
  25. {
  26. char *first, *next;

  27. if(!isascii(delim))
  28. {       fprintf(stderr,"delim error\n");
  29.         return NULL;
  30. }

  31. if (n <= 0)
  32. {       fprintf(stderr,"n too small\n");
  33.         return NULL;
  34. }

  35. if (n == 1)
  36. {
  37.         first = strchr(linebuf,delim);
  38.         if (first == NULL)
  39.                 {
  40.                         strcpy(wordbuf,linebuf);
  41.                         return wordbuf;
  42.                 }
  43.         strncpy(wordbuf,linebuf,first-linebuf);
  44.         wordbuf[first-linebuf] = '\0';
  45.                 return wordbuf;
  46. }

  47. //n => 2
  48. if((first = strnchr(linebuf,delim,n-1)) == NULL)
  49. {
  50.         fprintf(stderr,"not enough word separated by delim\n");
  51.         return NULL;
  52. }
  53. if((next =  strnchr(linebuf,delim,n)) == NULL)
  54.         strcpy(wordbuf,first+1);
  55. else
  56.         {
  57.                 strncpy(wordbuf,first+1,next-first-1);
  58.                 wordbuf[next-first-1] = '\0';
  59.         }
  60. return wordbuf;

  61. }
复制代码
发表于 2003-10-15 10:01:15 | 显示全部楼层
first = strchr(s,c);
for(i = 2;i <= n;i++)
{
first++;
first = strchr(first,c);
if (first == NULL)
        break;
}
return first;
这里有问题
检查一下吧
 楼主| 发表于 2003-10-15 11:43:06 | 显示全部楼层
不好意思,我检查了半天也没有检查出毛病来。
麻烦斑竹说的再清楚点好吗?谢谢!
发表于 2003-10-15 21:13:01 | 显示全部楼层
我刚也写了一个,大概测试了一下
我的第三个参数是delims,可以传入几个分隔符的字符串,比如" \t"(空格和制表符)

  1. char *
  2. getnword(char *linebuf,char *wordbuf,char *delims, int n)
  3. {
  4.   int len, begin, end = 0;
  5.   int num = 0;

  6.   if(!linebuf || !wordbuf || !delims || n < 1)
  7.     return(NULL);
  8.   len = strlen(linebuf);
  9.   begin = strspn(linebuf, delims);
  10.   end = begin + strcspn(linebuf + begin, delims);
  11.   while(begin < end && begin < len){
  12.     if(!strncmp(wordbuf, linebuf + begin, end - begin))
  13.       if(++num == n)
  14.         return(linebuf + begin);
  15.     begin = end + strspn(linebuf + end, delims);
  16.     end = begin + strcspn(linebuf + begin, delims);
  17.   }
  18.   return(NULL);
  19. }
复制代码
发表于 2003-10-15 23:30:29 | 显示全部楼层
first = strchr(s,c);   //如果为NULL
for(i = 2;i <= n;i++)
{
first++;//
first = strchr(first,c);//访问非法地址
if (first == NULL)

我没有调试
你试看是不是这样
 楼主| 发表于 2003-10-16 09:44:43 | 显示全部楼层
first = strchr(s,c); //如果为NULL
for(i = 2;i <= n;i++)
{
first++;//
first = strchr(first,c);//访问非法地址
if (first == NULL)

我没有调试
你试看是不是这样


谢谢!正如你所说的,存在这个毛病的。我已经改正
加了一个判断,不知道还有没有更好的方法。
再次表示感谢。

  1. first = strchr(s,c); //如果为NULL
  2. if (first == NULL)
  3.    return NULL
  4. for(i = 2;i <= n;i++)
  5. ……
复制代码
 楼主| 发表于 2003-10-16 10:21:18 | 显示全部楼层
最初由 libinary 发表
我刚也写了一个,大概测试了一下
我的第三个参数是delims,可以传入几个分隔符的字符串,比如" \t"(空格和制表符)

  1. char *
  2. getnword(char *linebuf,char *wordbuf,char *delims, int n)
  3. {
  4.   int len, begin, end = 0;
  5.   int num = 0;

  6.   if(!linebuf || !wordbuf || !delims || n < 1)
  7.     return(NULL);
  8.   len = strlen(linebuf);
  9.   begin = strspn(linebuf, delims);
  10.   end = begin + strcspn(linebuf + begin, delims);
  11.   while(begin < end && begin < len){
  12.     if(!strncmp(wordbuf, linebuf + begin, end - begin))
  13.       if(++num == n)
  14.         return(linebuf + begin);
  15.     begin = end + strspn(linebuf + end, delims);
  16.     end = begin + strcspn(linebuf + begin, delims);
  17.   }
  18.   return(NULL);
  19. }
复制代码


测试了一下,结果不对,我看不懂的地方是
if(!strncmp(wordbuf, linebuf + begin, end - begin))
能大概解释一下吗?
我调试了一下,wordbuf中一直是为空的。
我看ctrncmp应该为strncpy吧??若是的话还是调不通。我再看看
谢谢!

你们的帮助是我前进的动力!
发表于 2003-10-17 02:10:45 | 显示全部楼层
呵呵,都怪我一开始没看清,我的函数是搜索linebuf中的第n个wordbuf,比如getnword("ab aa ab\t ac ab", "ab", " \t", 3),就会返回第三个"ab",这个都怪我。

大概改了一下:

  1. char *
  2. getnword(char *linebuf,char *wordbuf,char *delims, int n)
  3. {
  4.   int len, begin, end = 0;
  5.   int num = 0;

  6.   if(!linebuf || !wordbuf || !delims || n < 1)
  7.     return(NULL);
  8.   len = strlen(linebuf);
  9.   begin = strspn(linebuf, delims);
  10.   end = begin + strcspn(linebuf + begin, delims);
  11.   while(begin < end && begin < len){
  12.     if(++num == n){
  13.       strncpy(wordbuf, linebuf + begin, end - begin);
  14.       wordbuf[end - begin] = '\0';
  15.       return(wordbuf);
  16.     }
  17.     begin = end + strspn(linebuf + end, delims);
  18.     end = begin + strcspn(linebuf + begin, delims);
  19.   }
  20.   return(NULL);
  21. }
复制代码
 楼主| 发表于 2003-10-17 08:07:44 | 显示全部楼层
再次表示谢谢!!
昨天看了斑竹的代码,得到了启发,知道用strspn系列函数可以实现我需要的结果,本想自己马上改一下,但是由于别的事情耽误了。没想到斑竹这么热心,这么快就发出来了。没给我机会
斑竹这个段代码全部用库函数,应该比我的效率高多了,并且没有了缓冲区溢出的可能。谢谢!
发表于 2003-10-17 08:50:12 | 显示全部楼层
说到缓冲区溢出,我对这个函数还是有点不满意,主要是wordbuf,因为没有办法确定linebuf中的第n个词的长度,所以还是有问题,我考虑了一下,有三种办法:
1、直接修改linebuf,把第n个词后面的分隔符改成'\0',直接返回wordbuf = linebuf + begin
2、函数内部声明一个static char *buf;每次动态分配,返回wordbuf = buf
3、函数声明改成int getnword(char *linebuf,char *wordbuf,char *delims, int n),返回第n个词的长度,如果调用者保证wordbuf够大可以直接调用,否则可以用
len = getnword(linebuf, NULL, delims, n);
先取得大小,再为wordbuf分配空间,再调用
getnword(linebuf, wordbuf, delims, n);
这里的函数内部要对wordbuf == NULL区别处理
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表