C函数之strtok使用及Win & BSD实现

这几天在学习TCP/IP Sockets in C(2nd) Practical Guide for Programmers,在学到如何确认Client和Server之间的数据传输时是一段数据的begin和end时,作者讲了两种方法:

第一种:每次传固定长度的数据,当然多长你要在Client和Server之间协调好。

第二种:规定begin和end的token-标记,(当然你传的数据要是出现你规定的token,也是有办法解决的,不是本文要说的)


好了,问题出来了,如何识别token来把token头和token尾之间真正的数据拿出来呢?

作者用到了本文的主角——strtok函数,翻《C程序设计语言》(我也想man的,可是deepin没装,奇怪~~~)看看如何说:


不晓得大家看不看得懂,反正我没咋看懂,不过应该能把token之间的数据分出来~~~

回来上网再查查,看看一半咋用它,要是能实现就最好了~~~

整理如下:

 strtok Sample Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* strtok example */
#include <stdio.h>
#include <string.h>

char *strtok_bsd( char *s,  const  char *delim);
char *strtok_win( char *s,  const  char *delim);

int main ()
{
     char str[] =  "- This, a sample string";
     char *pch;
    printf ( "Splitting string \"%s\" into tokens:\n", str);
    pch = strtok (str,  " ,.-");
     while (pch !=  NULL)
    {
        printf ( "%s\n", pch);
        pch = strtok ( NULL" ,.-");
    }
     return  0;
}

 strtok_bsd Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//在NetBSD中strtok的实现:
char  *strtok_r_bsd( char *s,  const  char *delim)
{
     const  char *spanp;   //span表示分隔,p表示指针
     char c, sc;          //c表示char字符,sc表示 span char
     char *tok;           //token表示分隔的段
     static  char *last;   //把last设置为一个静态局部变量来保存余下内容的地址。

     //当开始结尾都为NULL的时候,说明没有字符被查找,所以返回NULL
     if (s ==  NULL  && (s = *last) ==  NULL)
         return ( NULL);
     //由goto组成的循环是在扫描字符串的时候,当遇到所需要匹配的字符时,略过这个字符。
cont:
    c = *s++;
     for (spanp = delim; (sc = *spanp++) !=  0; )
    {
         if (c == sc)
             goto cont;
    }
     //下一个字符为0,则表示到达了搜索结果,把last置为NULL,并返回NULL
     if (c ==  0)
    {
        *last =  NULL;
         return ( NULL);
    }
     //把原始的字符串指针回退。
    tok = s -  1;
     //开始扫描字符串中是否含有要匹配的字符,之后把这个匹配字符之前的部分返回。
     //这看似是个无限循环,但当源字符串和匹配字符串都走到结尾时,也就是s和sc都为NULL时,最外层循环最后会走到return(tok)结束循环。
     for (;;)
    {
        c = *s++;
        spanp = delim;
         do
        {
             if ((sc = *spanp++) == c)
            {
                 if (c ==  0)
                    s =  NULL;
                 else
                    s[- 1] =  0;
                *last = s;
                 return (tok);
            }
        }
         while (sc !=  0);
    }
}

 strtok_win Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//在Microsoft中strtok的实现:
char  *strtok_win( char *s,  const  char *delim)
{
     static  unsigned  char *last;  //保存分隔后剩余的部分
     unsigned  char *str;          //返回的字符串
     const  unsigned  char *ctrl = ( const  unsigned  char *)delim;  //分隔字符

     //把分隔字符放到一个索引表中。定义32是因为ASCII字符表最多是0~255个,也是说用最大的255右移3位,也就是除以8一定会是32中的一个数。
     unsigned  char map[ 32];
     int count;

     //把map全部清为0,之后相与的操作,与0的都为0
     for (count =  0; count <  32; count++)
        map[count] =  0;

     //把匹配字符放入表中
     //放入的算法是把匹配字符右移3位,相当于除以8,的数值 并上(加上)
     //匹配字符与7,得到低3位,得出的结果,是把1左移的位数。最大左移位数是7,也就是所表示的最大值是128,
     do
    {
        map[*ctrl >>  3] |= ( 1 << (*ctrl &  7));
    }
     while (*ctrl++);

     //原始字符串是否为空,如果为空表示第二次获取剩余字符的分隔部分。
     if (s)
        str = ( unsigned  char *)s;
     else
        str = last;

     //在表中查找是否有匹配的字符,如果有略过
     while ((map[*str >>  3] & ( 1 << (*str &  7)))  && *str)
        str++;
     //重置需要扫描的字符串
    s = ( char *)str;
     //开始扫描
     for ( ; *str; str++)
    {
         if ( map[*str >>  3] & ( 1 << (*str &  7)))
        {
            *str++ =  '\0'; //当找到时,把匹配字符填为0,并且把str指向下一位。
             break//退出循环
        }
    }
    last = str;  // 把剩余字符串的指针保存到静态变量last中。

     if (s == ( char *)str)
         return  NULL//没有找到,也就是没有移动指针的位置,返回NULL
     else
         return s;  //找到了,返回之前字符串的头指针
}

ps:将strtok换成strtol_bsd和strtok_win就ok了,再单步调试看看~~~


NetBSD的方法是节约了空间,牺牲了时间(它的时间复杂度为N2),而微软的方法是节约了时间(它的时间复杂度为N),牺牲了空间(开了一个32个8位的空间。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值