首页 > 编程 > .NET > 正文

C标准库源码解剖(5):字符串处理函数string.h和wchar.h(续)

2024-07-10 13:27:15
字体:
来源:转载
供稿:网友

 3、字符串复制strcpy,strncpy,wcscpy,wcsncpy:将字符串src(或其前n个字符)复制到dest中,覆盖dest的内容。实现中先检查指针是否越界,计算指针dest到src的偏移,然后开始做复制操作,复制到dest的开始位置处,以覆盖dest的内容。对strncpy,也采用了每4个字符作为一组来进行复制的方法,以加快复制速度。

 

[cpp] view plaincopy
  1. /* strcpy.c:strcpy函数的实现 */  
  2. #include <stddef.h>   /* 用到了ptrdiff_t */  
  3. #include <string.h>  
  4. #include <memcopy.h>  
  5. #include <bp-checks.h>  /* 定义了CHECK_BOUNDS_LOW和CHECK_BOUNDS_HIGH */  
  6. #undef strcpy  
  7. /* 将SRC复制到DEST中,覆盖DEST原先的内容 */  
  8. char *  
  9. strcpy (dest, src)  
  10.      char *dest;  
  11.      const char *src;  
  12. {  
  13.   reg_char c;  
  14.   /* 检查指针src的值是否 >= low,返回原来的指针值 */  
  15.   char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);  
  16.   /* 计算出目的地dest到s的偏移 */  
  17.   const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;  
  18.   size_t n;  
  19.   do  
  20.     {  
  21.       c = *s++;   /* 把src中每个字符复制到目的地,覆盖了dest中的内容 */  
  22.       s[off] = c;  
  23.     }  
  24.   while (c != '/0');  
  25.   n = s - src;  
  26.   (void) CHECK_BOUNDS_HIGH (src + n); /* 检查指针src+n的值是否 < high,返回原来的指针值 */  
  27.   (void) CHECK_BOUNDS_HIGH (dest + n);  
  28.   return dest;  
  29. }  
  30. libc_hidden_builtin_def (strcpy)  

 

 

[cpp] view plaincopy
  1. /* strncpy.c:strncpy函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h>  
  4. #undef strncpy  
  5. /* 将s2的前n个字符复制到s1中,覆盖s1原先的内容,若s2不中n个字符, 
  6.     则填充null字符,直到写入n个字符 */  
  7. char *  
  8. strncpy (s1, s2, n)  
  9.      char *s1;  
  10.      const char *s2;  
  11.      size_t n;  
  12. {  
  13.   reg_char c;  
  14.   char *s = s1;  
  15.   --s1; /* 指向首字符的前一个字符 */  
  16.   if (n >= 4)     /* 做复制操作,每4个字符作为一组来进行复制 */  
  17.     {  
  18.       size_t n4 = n >> 2; /* 让n除以4,计算出循环次数 */  
  19.       for (;;)   /* 每次循环都复制4个字符,总共复制了4*n4个字符 */  
  20.     {  
  21.       c = *s2++;  
  22.       *++s1 = c;  
  23.       if (c == '/0'/* s2不足n个字符时,复制完毕,退出循环 */  
  24.         break;  
  25.       c = *s2++;  
  26.       *++s1 = c;  
  27.       if (c == '/0')  
  28.         break;  
  29.       c = *s2++;  
  30.       *++s1 = c;  
  31.       if (c == '/0')  
  32.         break;  
  33.       c = *s2++;  
  34.       *++s1 = c;  
  35.       if (c == '/0')  
  36.         break;  
  37.       if (--n4 == 0)  
  38.         goto last_chars; /* 循环终止,要对剩下的几个字符(不超过3个)进行复制 */  
  39.     }  
  40.       n = n - (s1 - s) - 1;  
  41.       if (n == 0)  /* 若s1恰好到达s的终止符的前一个字符处 */  
  42.     return s;  /* 说明s与s2长度相等,均为n,复制操作恰好用s2覆盖了s,终止符没有覆盖,直接返回s */  
  43.       goto zero_fill; /* 否则s1没有到达s的末尾,说明s2不足n个字符,需要在s1末尾填充null字符,直到写入n个字符 */  
  44.     }  
  45.  last_chars:  
  46.   n &= 3; /* 求出n除以4的余数 */  
  47.   if (n == 0)  /* 余数为0说明没有剩余的未复制的字符,直接返回s */  
  48.     return s;  
  49.   do   /* 对剩下的几个字符(最多3个)进行复制 */  
  50.     {  
  51.       c = *s2++;  
  52.       *++s1 = c;  
  53.       if (--n == 0)  
  54.     return s;  
  55.     }  
  56.   while (c != '/0');  
  57.  zero_fill:  
  58.   do  
  59.     *++s1 = '/0';  /* 在s1末尾填充null字符,直到写入n个字符 */  
  60.   while (--n > 0);  
  61.   return s;  
  62. }  
  63. libc_hidden_builtin_def (strncpy)  

 

    4、字符串求长strlen,wcslen:返回str中终止符'/0'之前的字符个数。这里通过把指针移到终止符处,然后计算该指针与开始处指针的差值来获取字符串的长度。为了加快移动速度,实现中把const char*型指针char_ptr转换成了unsigned long*型指针longword_ptr,这样一次就可以移动4个字节。算法关键是要辨别出longword_ptr指向的值(有4个字节)中有一个字节为0(它表示字符'/0'),这说明指针到达了终止符'/0'处,要停止移动,并转换回const char*型指针,计算指针之间的差值。

 

[cpp] view plaincopy
  1. /* strlen.c:strlen函数的实现 */  
  2. #include <string.h>  
  3. #include <stdlib.h>  /* 用到abort()函数 */  
  4. #undef strlen  
  5. /* 返回以null终止的字符串str的长度。通过一次测试4个字节来迅速的扫描到null终止符 */  
  6. size_t  
  7. strlen (str)  
  8.      const char *str;  
  9. {  
  10.   const char *char_ptr;  
  11.   const unsigned long int *longword_ptr;  
  12.   unsigned long int longword, magic_bits, himagic, lomagic;  
  13.   /* 通过一次读取一个字符来处理开头的几个字符,直到char_ptr中的值对齐到一个long型字的边界, 
  14.       即直到char_ptr中的值是long的字节数(通常为4)的倍数 */  
  15.   for (char_ptr = str; ((unsigned long int) char_ptr  
  16.             & (sizeof (longword) - 1)) != 0;  
  17.        ++char_ptr)  
  18.     if (*char_ptr == '/0'/* 若到达null终止符,则直接返回长度 */  
  19.       return char_ptr - str;  
  20.   /* 所有这些说明性的注释使用4字节的long型字,但本算法同样也可以应用于8字节的long型字 */  
  21.     
  22.   longword_ptr = (unsigned long int *) char_ptr;  
  23.   /* magic_bits的第8,16,24,31位为0,称这些位为“洞”。注意每个字节的左边有一个洞, 
  24.       在最后的位置上也有一个洞。 
  25.      bits:  01111110 11111110 11111110 11111111 
  26.       比特1确保进位能传播到后面的比特0上,比特0则提供洞,以便让进位陷进去  */  
  27.   magic_bits = 0x7efefeffL;  
  28.   himagic = 0x80808080L;  /* 高位魔数,即第7,15,23,31位上为1 */  
  29.   lomagic = 0x01010101L;  /* 低位魔数,即第0,8,16,24位上为1 */  
  30.   if (sizeof (longword) > 4) /*  64位的平台上 */  
  31.     {  
  32.       /* 魔数的64位版本 */  
  33.       /* 移位操作分两步,以避免当long为32位时出现警告 */  
  34.       /* 位数的第8,16,24,32,40,48,56,63位上为0 */  
  35.       magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL;  
  36.       himagic = ((himagic << 16) << 16) | himagic; /* 第7,15,23,31,39,47,55,63位上为1 */  
  37.       lomagic = ((lomagic << 16) << 16) | lomagic; /* 第0,8,16,24,32,40,48,56位上为0 */  
  38.     }  
  39.   if (sizeof (longword) > 8) /* long类型大于8字节则终止程序 */  
  40.     abort ();  
  41.   /* 这里我们不使用传统的对每个字符都进行测试的循环,而是一次测试一个long型字。技巧性的部分 
  42.       是测试当前long型字的各个字节是否为0 */  
  43.   for (;;)  
  44.     {      
  45.       longword = *longword_ptr++;  
  46.       if (  
  47. #if 0  
  48.       /* 让longword加上魔数magic_bits  */  
  49.       (((longword + magic_bits)  
  50.         /* 设置那些通过加法而未改变的位 */  
  51.         ^ ~longword)  
  52.          
  53.        /* 只需看这些洞。如果任何的洞位都没有改变,最有可能的是有一个字节值为0 */  
  54.        & ~magic_bits)  
  55. #else  
  56.       ((longword - lomagic) & himagic)  
  57. #endif  
  58.       != 0)  
  59.     {       
  60.       /* 长整型字的哪个字节为0?如果都不为0,则是一个非预期情况,继续搜索 */  
  61.       const char *cp = (const char *) (longword_ptr - 1);  
  62.       if (cp[0] == 0)  
  63.         return cp - str;  
  64.       if (cp[1] == 0)  
  65.         return cp - str + 1;  
  66.       if (cp[2] == 0)  
  67.         return cp - str + 2;  
  68.       if (cp[3] == 0)  
  69.         return cp - str + 3;  
  70.       if (sizeof (longword) > 4) /* 如果long类型是8个字节,则还有4个字节需要判断 */  
  71.         {  
  72.           if (cp[4] == 0)  
  73.         return cp - str + 4;  
  74.           if (cp[5] == 0)  
  75.         return cp - str + 5;  
  76.           if (cp[6] == 0)  
  77.         return cp - str + 6;  
  78.           if (cp[7] == 0)  
  79.         return cp - str + 7;  
  80.         }  
  81.     }  
  82.     }  
  83. }  
  84. libc_hidden_builtin_def (strlen)  

 

    解释:
    (1)先移动char_ptr,使其值对齐到长整型字的边界,即移动到使char_ptr中的值是4的倍数为止。在对齐过程中若到达了终止符处,则直接返回与开始处的指针str的差值。 
    (2)对longword_ptr指针进行移动时,指针指向的值为longword。为了判断指针是否到达终止符,算法实现使用了两个魔数lomagic和himagic,lomagic各个字节的最低位为1,其余位均为0;himagic各个字节的最高位为1,其余位均为0。看表达式(longword - lomagic) & himagic,若longword中有一个字节为00000000,则减00000001时要向高字节借一位,得到11111111或11111110(当借了一位给更低的字节时),与10000000做“与”运算后变成10000000,这时表达式的结果必定不为0。可见,只有在表达式结果不等于0时,longword中才有可能有终止符。因此,在移动过程中,一旦表达式结果不等于0,只要逐一检查一下每个字节,看哪个为0,这时就到达终止符,计算指针差值并返回。若都不为0,则继续移动。
    (3)也可以只用一个魔数magic_bits来实现,即代码中用#if 0注释掉的那部分,它可以达到同样的效果。看表达式((longword + magic_bits) ^ ~longword) & ~magic_bits,最后的“与”运算会使结果的其他位清零,只留下那4个洞位,因此我们只要看longword的洞位的变化即可。若longword中有一个字节为0,则做加法后它不可能向高字节(即左侧字节)进位,左侧字节的洞位没有改变(因为magic_bits的对应洞位为0,加上0而又没有低字节的进位,因此不会改变)。做异或运算后,必定使这个洞位变成1,因此表达式的结果必定不为0。可见,这跟(2)用两个魔数实现的效果是一样的。
    5、字符搜索strchr,strrchr,wcschr,wcsrchr:在字符串s中查找字符c的第一次(或最后一次)出现,若没找到则返回NULL指针。算法实现与strlen类似,只不过在strlen是搜索到终止符'/0'为止,这里是搜索到字符c为止。

 

[cpp] view plaincopy
  1. /* strchr.c:strchr函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h>  /* 非标准头文件,要用到reg_char类型 */  
  4. #include <stdlib.h>   /* 要用到abort() */  
  5. #undef strchr  
  6. /* 在S中查找C的第一次出现,如果没有找到,则返回NULL指针  */  
  7. char *  
  8. strchr (s, c_in)  
  9.      const char *s;  
  10.      int c_in;  
  11. {  
  12.   const unsigned char *char_ptr;  
  13.   const unsigned long int *longword_ptr;  
  14.   unsigned long int longword, magic_bits, charmask;  
  15.   unsigned reg_char c;  
  16.   c = (unsigned char) c_in;  
  17.   /* 通过一次读取一个字符来处理开头的几个字符,直到char_ptr中的值对齐到一个long型字的边界, 
  18.       即直到char_ptr中的值是long的字节数(通常为4)的倍数 */  
  19.   for (char_ptr = (const unsigned char *) s;  
  20.        ((unsigned long int) char_ptr & (sizeof (longword) - 1)) != 0;  
  21.        ++char_ptr)  
  22.     if (*char_ptr == c)     /* 若到达字符c处,则直接返回其指针 */  
  23.       return (void *) char_ptr;  
  24.     else if (*char_ptr == '/0')  /* 没找到c则返回NULL */  
  25.       return NULL;  
  26.   /* 所有这些说明性的注释使用4字节的long型字,但本算法同样也可以应用于8字节的long型字 */  
  27.   longword_ptr = (unsigned long int *) char_ptr;  
  28.   /* magic_bits的第8,16,24,31位为0,称这些位为“洞”。注意每个字节的左边有一个洞, 
  29.       在最后的位置上也有一个洞。 
  30.      bits:  01111110 11111110 11111110 11111111 
  31.       比特1确保进位能传播到后面的比特0上,比特0则提供洞,以便让进位陷进去  */  
  32.   switch (sizeof (longword))  
  33.     {  
  34.     case 4: magic_bits = 0x7efefeffL; break;  
  35.     case 8: magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; break;  
  36.     default:  
  37.       abort ();  
  38.     }  
  39.   /* 设置一个长整型字,其每个字节都是字符c */  
  40.   charmask = c | (c << 8);  
  41.   charmask |= charmask << 16;  
  42.   if (sizeof (longword) > 4)  
  43.     /* 移位操作分两步,以避免当long为32位时出现警告 */  
  44.     charmask |= (charmask << 16) << 16;  
  45.   if (sizeof (longword) > 8)   
  46.     abort ();  /* long类型大于8字节则终止程序 */  
  47.   /* 这里我们不使用传统的对每个字符都进行测试的循环,而是一次测试一个long型字。技巧性的部分 
  48.       是测试当前long型字的各个字节是否为0 */  
  49.   for (;;)  
  50.     {      
  51.       longword = *longword_ptr++;  
  52.       /* 让longword加上魔数magic_bits  */  
  53.       if ((((longword + magic_bits)  
  54.         /* 设置那些通过加法而未改变的位 */  
  55.         ^ ~longword)  
  56.        /* 只需看这些洞。如果任何的洞位都没有改变,最有可能的是有一个字节值为0 */  
  57.        & ~magic_bits) != 0 ||  
  58.       /* 捕捉到值为0的字节后,测试字中是否含有字符c  */  
  59.       ((((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask))  
  60.        & ~magic_bits) != 0)  
  61.     {  
  62.       /* 长整型字的哪个字节为C或0?如果都不是,则是一个非预期情况,继续搜索 */  
  63.       const unsigned char *cp = (const unsigned char *) (longword_ptr - 1);  
  64.       if (*cp == c)  
  65.         return (char *) cp;  
  66.       else if (*cp == '/0')  
  67.         return NULL;  
  68.       if (*++cp == c)  
  69.         return (char *) cp;  
  70.       else if (*cp == '/0')  
  71.         return NULL;  
  72.       if (*++cp == c)  
  73.         return (char *) cp;  
  74.       else if (*cp == '/0')  
  75.         return NULL;  
  76.       if (*++cp == c)  
  77.         return (char *) cp;  
  78.       else if (*cp == '/0')  
  79.         return NULL;  
  80.       if (sizeof (longword) > 4) /* 如果long类型是8个字节,则还有4个字节需要判断 */  
  81.         {  
  82.           if (*++cp == c)  
  83.         return (char *) cp;  
  84.           else if (*cp == '/0')  
  85.         return NULL;  
  86.           if (*++cp == c)  
  87.         return (char *) cp;  
  88.           else if (*cp == '/0')  
  89.         return NULL;  
  90.           if (*++cp == c)  
  91.         return (char *) cp;  
  92.           else if (*cp == '/0')  
  93.         return NULL;  
  94.           if (*++cp == c)  
  95.         return (char *) cp;  
  96.           else if (*cp == '/0')  
  97.         return NULL;  
  98.         }  
  99.     }  
  100.     }  
  101.   return NULL;  
  102. }  
  103. #ifdef weak_alias  
  104. #undef index  
  105. weak_alias (strchr, index)  
  106. #endif  
  107. libc_hidden_builtin_def (strchr)  

 

 

[cpp] view plaincopy
  1. /* strrchr.c:strrchr函数的实现 */  
  2. #include <string.h>  
  3. #undef strrchr  
  4. /* 在S中查找C的最后一次出现  */  
  5. char *  
  6. strrchr (const char *s, int c)  
  7. {  
  8.   register const char *found, *p;  
  9.   c = (unsigned char) c;  
  10.   /* 因为strchr非常地快,我们直接使用它来实现strrchr */  
  11.   if (c == '/0')  
  12.     return strchr (s, '/0');  
  13.   found = NULL;  
  14.   while ((p = strchr (s, c)) != NULL)  
  15.     {  
  16.       found = p;  
  17.       s = p + 1;  
  18.     }  
  19.   return (char *) found;  
  20. }  
  21. #ifdef weak_alias  
  22. #undef rindex  
  23. weak_alias (strrchr, rindex)  
  24. #endif  
  25. libc_hidden_builtin_def (strrchr)  

 

    解释:
    (1)算法中,有可能搜索到字符c,也有可能搜索到终止符(当字符串中没有c时)。对于搜索到终止符,与strlen中一样,对于搜索到字符c,要判断longword中是否有一个字节为c,看表达式(((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask)) & ~magic_bits,长整型字charmask的每个字节都是字符c。strlen的对应表达式中的longword换成了这里的longword ^ charmask,而这里的longword中有一个字节为c,恰好等价于longword ^ charmask中有一个字节为0,因此具体的分析过程是一样的。
    (2)strrchr的实现直接使用strchr。用strchr不停地向前搜索,直到搜索到最后一个c为止。
    6、子串的无顺序匹配strspn,strcspn,strpbrk,wcsspn,wcscspn,wcspbrk:strspn和strcspn在s的开头查找一个最长子串,使其所有字符都在accept中(或都不在reject中),返回这个子串的长度。strspn的实现中直接对s中开头的每个字符搜索accept,看其是否在accept中。strcspn的实现则使用了strchr来查找字符。strpbrk在s中搜索第一个出现在accept中的字符,返回其指针。

 

[cpp] view plaincopy
  1. /* strspn.c:strspn函数的实现 */  
  2. #include <string.h>  
  3. #undef strspn  
  4. /* 返回S中的第一个子串长度,这个子串的所有字符都在ACCEPT中  */  
  5. size_t  
  6. strspn (s, accept)  
  7.      const char *s;  
  8.      const char *accept;  
  9. {  
  10.   const char *p;  
  11.   const char *a;  
  12.   size_t count = 0;  
  13.   for (p = s; *p != '/0'; ++p) /* 对s开头的各个字符,搜索accept */  
  14.     {  
  15.       for (a = accept; *a != '/0'; ++a)  
  16.     if (*p == *a)  /* 若该字符在accept中,则子串长度加1 */  
  17.       break;  
  18.       if (*a == '/0'/* 若在accept中没有找到该字符,则子串匹配结束,直接返回count */  
  19.     return count;  
  20.       else  
  21.     ++count;  
  22.     }  
  23.   return count;  
  24. }  
  25. libc_hidden_builtin_def (strspn)  

 

 

[cpp] view plaincopy
  1. /* strcspn.c:strcspn函数的实现 */  
  2. #if HAVE_CONFIG_H  
  3. # include <config.h>  
  4. #endif  
  5. #if defined _LIBC || HAVE_STRING_H  
  6. # include <string.h>  
  7. #else  
  8. # include <strings.h>  
  9. # ifndef strchr  
  10. #  define strchr index  
  11. # endif  
  12. #endif  
  13. #undef strcspn  
  14. /* 返回S中的第一个子串长度,这个子串的所有字符都不在REJECT中  */  
  15. size_t  
  16. strcspn (s, reject)  
  17.      const char *s;  
  18.      const char *reject;  
  19. {  
  20.   size_t count = 0;  
  21.   while (*s != '/0')  /* 对s开头的各个字符,搜索reject */  
  22.     if (strchr (reject, *s++) == NULL) /* 若不在reject,则子串长度加1 */  
  23.       ++count;  
  24.     else  
  25.       return count;  
  26.   return count;  
  27. }  
  28. libc_hidden_builtin_def (strcspn)  

 

 

[cpp] view plaincopy
  1. /* strpbrk.c:strpbrk函数的实现  */  
  2. #ifdef HAVE_CONFIG_H  
  3. # include <config.h>  
  4. #endif  
  5. #if defined _LIBC || defined HAVE_CONFIG_H  
  6. # include <string.h>  
  7. #endif  
  8. #undef strpbrk  
  9. /* 在s中搜索第一个出现在accept中的字符,返回其指针 */  
  10. char *  
  11. strpbrk (s, accept)  
  12.      const char *s;  
  13.      const char *accept;  
  14. {  
  15.   while (*s != '/0'/* 对s开头的各个字符,看其是否在accept中 */  
  16.     {  
  17.       const char *a = accept;  
  18.       while (*a != '/0')  
  19.     if (*a++ == *s) /* 若在accept,则返回,否则继承向前搜索 */  
  20.       return (char *) s;  
  21.       ++s;  
  22.     }  
  23.   return NULL;  
  24. }  
  25. libc_hidden_builtin_def (strpbrk)  

 

    7、模式匹配及字符串解析strstr,strtok,wcsstr,wcstok:strstr(src,sub)在src中搜索子串sub,返回其第一次出现的位置。strtok(str,set)用set中的字符作为分隔符把str分解为多个标号。
    strstr的实现用了最新的二路模式匹配算法,可以达到最好的效率。由于算法比较复杂,涉及到很多内部函数,这里就不解剖了,我们平时一般使用KMP算法来进行模式匹配,这个效率也已经非常不错了。strtok实现如下:

 

[cpp] view plaincopy
  1. /* strok.c:strok函数的实现  */  
  2. #include <string.h>  
  3. static char *olds; /* 下一记号的开始处,若到达字符串末尾,则olds指向终止符'/0' */  
  4. #undef strtok  
  5. /* 用DELIM中的字符作为分隔符把S解析成多个记号,返回当前的记号。如果S为NULL, 
  6.     则strtok从即下一记号的开始处开始解析。例如: 
  7.     char s[] = "-abc-=-def"; 
  8.     x = strtok(s, "-");     // x = "abc" 
  9.     x = strtok(NULL, "-=");     // x = "def" 
  10.     x = strtok(NULL, "=");      // x = NULL 
  11.         // s = "abc/0=-def/0" 
  12. */  
  13. char *  
  14. strtok (s, delim)  
  15.      char *s;  
  16.      const char *delim;  
  17. {  
  18.   char *token;  
  19.   if (s == NULL) /* s指定为NULL,则使用olds */  
  20.     s = olds;  
  21.   /* 从s开始搜索分隔符,跳过分隔符,让s移动到记号开始处  */  
  22.   s += strspn (s, delim);  
  23.   if (*s == '/0'/* 若s到达字符串末尾,则返回NULL表示记号解析过程完毕 */  
  24.     {  
  25.       olds = s;  
  26.       return NULL;  
  27.     }  
  28.   /* 找到当前记号的末尾处(即下一分隔符处)  */  
  29.   token = s; /* token指向记号的首个字符 */  
  30.   s = strpbrk (token, delim); /* 从token开始找到下一分隔符,让s指向它 */  
  31.   if (s == NULL) /* 如果到达的是字符串末尾,说明当前记号是最后一个记号 */  
  32.     /* 从token开始,找到终止符,并赋给olds,表示记号解析结束  */  
  33.     olds = __rawmemchr (token, '/0');  
  34.   else  /* 否则s指向了下一分隔符 */  
  35.     {  
  36.       /* 把分隔符替换成'/0',以解析出当前记号,让OLDS指向下一记号的开始处  */  
  37.       *s = '/0';  
  38.       olds = s + 1;  
  39.     }  
  40.   return token;  
  41. }  

 

    算法先用strspn函数使s路过分隔符,移到当前记号的开始处;接着让token指向当前记号开始处,s移到下一个分隔符处(通过strpbrk函数);然后把这个分隔符替换成终止符'/0',以解析出当前记号,olds指向下一记号的开始处。下一次解析时,若指定s为NULL,则从olds处开始新的解析。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表