当前位置:编程学习 > C#/ASP.NET >>

strlok源代码理解

看到strlok的源代码,有几个地方不明白,高手指教。

函数实现的功能:
原型:extern char *strtok(char *s, char *delim);
用法:#include <string.h>
功能:分解字符串为一组标记串。s为要分解的字符串,delim为分隔符字符串。 
说明:首次调用时,s必须指向要分解的字符串,随后调用要把s设成NULL。
strtok在s中查找包含在delim中的字符并用NULL('\0')来替换,直到找遍整个字符串。
返回指向下一个标记串。当没有标记串时则返回空字符NULL。


char * __cdecl strtok (char * string,const char * control)
{
        unsigned char *str;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

#ifdef _MT
        _ptiddata ptd = _getptd();
#else  /* _MT */
        static char *nextoken;
#endif  /* _MT */

        /* Clear control map */
        for (count = 0; count < 32; count++)
                map[count] = 0;

        //下面这段代码是做什么用的啊?特别是 map[*ctrl >> 3] |= (1 << (*ctrl & 7))是实现什么啊?????
        do {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
        } while (*ctrl++);

        
        if (string)
                str = string;
        else
#ifdef _MT
                str = ptd->_token;
#else  /* _MT */
                str = nextoken;
#endif  /* _MT */

         while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
            str++;

        string = str;

       
//这个也不是很明白
for ( ; *str ; str++ )
           if ( map[*str >> 3] & (1 << (*str & 7)) ) {
                     *str++ = '\0';
                        break;
                }

#ifdef _MT
        ptd->_token = str;
#else  /* _MT */
        nextoken = str;
#endif  /* _MT */

        if ( string == str )
                return NULL;
        else
                return string;
} --------------------编程问答-------------------- 帮忙 up
--------------------编程问答-------------------- 我也不是很清楚 
不过
unsigned char map[32];
map字符数组就像当与一个map表了
unsigned char的0-255被映射到map表里

//下面这段代码是做什么用的啊?特别是 map[*ctrl >> 3] |= (1 << (*ctrl & 7))是实现什么


这里的*ctrl >> 3 就像当于表号 
256个数被映射到32个表里的列数
而1 << (*ctrl & 7) 相当于表值
比如字符"01234567"
它们就会被映射到map(6)里 
而对应的map(6)对应的值就会是1111 1111 从左到右依次对应"01234567"里面的01234567。

这样做的好处就是节省空间了 至少我现在看来

if (string)
str = string;
else
#ifdef _MT
str = ptd->_token;
#else /* _MT */
str = nextoken;
#endif /* _MT */
就是第二次输入NULL的原因吧~

其他的也类似吧~

能力有限 出错不负责! --------------------编程问答-------------------- lmlmlmnew():
   map[*ctrl >> 3] |= (1 << (*ctrl & 7))

看了你说的这个,好象还是不太明白,能不能说详细点啊! --------------------编程问答-------------------- const unsigned char *ctrl = control;

*ctrl 是unsigned char 的 所以他的范围是0-255
*ctrl>>3  右移3位 相当于除8
0-255 除 8之后 就在 0-31之间

好比假设*ctrl = '0'的ASCII码为 48 
那么 *ctrl>>3 就是 6了
map[*ctrl>>3] 就相当于 map[6]

(1 << (*ctrl & 7))呢
(*ctrl & 7)就是1 左移的位数
比如'0'-'7'属于属于map6[6]里面的
假若 *ctrl = '0',因为(*ctrl & 7) = 0 所以 1就左移 1 << 0位, map[6] = 0000 0001
假若 *ctrl = '1',其ASCII为49也就是0011 0001, *ctrl & 7 = 0000 0001,所以1就左移 1 << 1位, 就是说map[6] = 0000 0010;
同理 *ctrl = '2', ASCII为 0011 0010,*ctrl & 7 = 2,所以1就左移 1 << 2,
map[6] = 0000 0100
因此可以看出 这个简单的运算把0-255的ASCII都映射到了 map[32]里面 这不就相当于减少了转换所需要的内存空间么.....
--------------------编程问答-------------------- map[*ctrl >> 3] |= (1 << (*ctrl & 7))
之所以用 |= 就是把*ctrl里面的所有字符都映射到map[6]里~~

结贴吧 大兄弟 就等你100分下锅呢。。。。
~不看功劳看苦劳~
虽然说的不定全对 不过打这么多字也不容易啊~ --------------------编程问答-------------------- 错了 
map[*ctrl >> 3] |= (1 << (*ctrl & 7))
之所以用 |= 就是要把*ctrl里面的所有字符通过循环都映射到map里~~ --------------------编程问答-------------------- lmlmlmnew() :
很感谢你,你说的大概明白了,不过还在进一步的查资料,你的分肯定是会给你的!
非常感谢!
--------------------编程问答-------------------- 以前对ASCII这个东西没仔细想,这下才知道这几个句子的用处了,还需多多努力,多多学习啊! --------------------编程问答-------------------- lmlmlmnew() :
do {
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
} while (*ctrl++);

这段中,你说是做256到32的映射,还是很同意的,但是对于映射的具体方式觉得你理解有误,首先(1 << (*ctrl & 7))我觉得是取(*ctrl)低3位然后右移(不是左移)即相当于除2,就是说取第2,3位,然后循环映射到map[*ctrl >> 3]上!

但是在后面的检测过程中:
//这个也不是很明白
for ( ; *str ; str++ )
if ( map[*str >> 3] & (1 << (*str & 7)) ) {
*str++ = '\0';
break;
}

这个过程实际上就是检册过程,但是还是不是很理解,如果说刚才ctr="0",0的ASCII码是48,则映射的时候把它映射到map[6]|=(1<<(*ctrl&7))=0,则map[6]=0;这个时候不满足判断的条件,则检测不到啊~ --------------------编程问答-------------------- 这段中,你说是做256到32的映射,还是很同意的,但是对于映射的具体方式觉得你理解有误,首先(1 << (*ctrl & 7))我觉得是取(*ctrl)低3位然后右移(不是左移)即相当于除2,就是说取第2,3位,然后循环映射到map[*ctrl >> 3]上!


首先 << 这个符号:

按位左移运算符 (<<)
左移表达式的位。
result = expression1 << expression2
参数
result
任何变量。
expression1
任何表达式。
expression2
任何表达式。
说明
<< 运算符把 expression1 的所有位向左移 expression2 指定的位数。例如:
var temp
temp = 14 << 2
变量 temp 的值为 56,因为 14 (即二进制的 00001110)向左移两位等于 56 (即二进制的 00111000)。 

我不知道你为什么说它是“(*ctrl)低3位然后右移”。
这是个左移的符号阿 不可能是右移的。 --------------------编程问答-------------------- 对于 << 这个运算符 没有左值和右值之分
常量也能作为左值的~~
--------------------编程问答-------------------- 但是在后面的检测过程中:
//这个也不是很明白
for ( ; *str ; str++ )
if ( map[*str >> 3] & (1 << (*str & 7)) ) {
*str++ = '\0';
break;
}

这个过程实际上就是检册过程,但是还是不是很理解,如果说刚才ctr="0",0的ASCII码是48,则映射的时候把它映射到map[6]|=(1<<(*ctrl&7))=0,则map[6]=0;这个时候不满足判断的条件,则检测不到啊~



这就得在调试中看看了,我也发现如果这么简单的理解的话还有一些问题。
手头没环境 得晚上回家去试试~~
不过得加班>.<"" --------------------编程问答-------------------- mark 学习 --------------------编程问答--------------------  
映射前:
map[6] = 0 | (00000001 << (00110000 & 00000111)
map[6] = 00000001  //map[6] 是第7组的标志, 一组8个元素。

验证:

map[*str   > >   3]   &   (1   < <   (*str   &   7))
map[6] & (00000001 << (00110000 & 00000111)
00000001 & 00000001 = 1 
验证成功,将下一位设置为*str++ = '\0'; over!
补充:.NET技术 ,  VC.NET
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,