首页 > 编程 > .NET > 正文

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

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

 string.h中包含了所有的字符串处理函数,也包含了内存处理函数,因为这些内存处理函数(如比如、复制、搜索)的功能与字符串处理函数功能类似。我们是用通用指针来指向内存块的,通用指针可以用char*类型(传统C语言),也可以用void*类型(标准C语言)。每个函数都有对应的宽字符版本,在wchar.h中。
    string.h中包含的标准库函数:strcat,strncat,strcmp,strncmp,strcpy,strncpy,strlen,strchr,strrchr,strspn,strcspn,strpbrk, strstr,strok,strcoll,strxfrm,strerror; memcpy,memmove,memcmp,memchr,memeset。GNU还提供了很多非标准的扩展,如memccpy,rawmemchr,memrchr, strdup,strndup等。

 

[cpp] view plaincopy
  1. /* ISO C99 Standard: 7.21 字符串处理 <string.h> */  
  2. #ifndef _STRING_H  
  3. #define _STRING_H   1  
  4. #include <features.h> /* 非标准头文件,定义了一些编译选项 */  
  5. __BEGIN_DECLS  
  6. /* 从<stddef.h>中获得size_t和NULL  */  
  7. #define __need_size_t  
  8. #define __need_NULL  
  9. #include <stddef.h>  
  10. __BEGIN_NAMESPACE_STD  
  11. /* 从SRC中复制N个字节的内容到DEST中  */  
  12. extern void *memcpy (void *__restrict __dest,  
  13.              __const void *__restrict __src, size_t __n)  
  14.      __THROW __nonnull ((1, 2));  
  15. /* 从SRC中复制N个字节的内容到DEST中,保证对重叠字符串(即SRC与DEST共用存储空间)有正确的行为 */  
  16. extern void *memmove (void *__dest, __const void *__src, size_t __n)  
  17.      __THROW __nonnull ((1, 2));  
  18. __END_NAMESPACE_STD  
  19. /* 从SRC中复制不超过N个字节的内容到DEST中,当遇到字符C时便停止,返回DEST中C的拷贝后面的字符指针。 
  20.     如果在SRC的前面N个字节中没有发现字符C,则返回NULL */  
  21. #if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN  
  22. extern void *memccpy (void *__restrict __dest, __const void *__restrict __src,  
  23.               int __c, size_t __n)  
  24.      __THROW __nonnull ((1, 2));  
  25. #endif /* SVID.  */  
  26. __BEGIN_NAMESPACE_STD  
  27. /* 把S的前N个字节的内容设置为C */  
  28. extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));  
  29. /* 比较S1和S2的前n字节的内容 */  
  30. extern int memcmp (__const void *__s1, __const void *__s2, size_t __n)  
  31.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  32. /* 在S的前N个字节中搜索C的第一次出现  */  
  33. extern void *memchr (__const void *__s, int __c, size_t __n)  
  34.       __THROW __attribute_pure__ __nonnull ((1));  
  35. __END_NAMESPACE_STD  
  36. #ifdef __USE_GNU  
  37. /* 在S中搜索C,这与“memchr”类似,但这里没有长度的限制 */  
  38. extern void *rawmemchr (__const void *__s, int __c)  
  39.      __THROW __attribute_pure__ __nonnull ((1));  
  40. /* 在S的前N个字节中搜索C的最后一次出现  */  
  41. extern void *memrchr (__const void *__s, int __c, size_t __n)  
  42.       __THROW __attribute_pure__ __nonnull ((1));  
  43. #endif  
  44. __BEGIN_NAMESPACE_STD  
  45. /* 将SRC复制到DEST中  */  
  46. extern char *strcpy (char *__restrict __dest, __const char *__restrict __src)  
  47.      __THROW __nonnull ((1, 2));  
  48. /* 将SRC的前N个字符复制到DEST  */  
  49. extern char *strncpy (char *__restrict __dest,  
  50.               __const char *__restrict __src, size_t __n)  
  51.      __THROW __nonnull ((1, 2));  
  52. /* 将SRC追加到DEST */  
  53. extern char *strcat (char *__restrict __dest, __const char *__restrict __src)  
  54.      __THROW __nonnull ((1, 2));  
  55. /* 将SRC的前N个字符追加到DEST */  
  56. extern char *strncat (char *__restrict __dest, __const char *__restrict __src,  
  57.               size_t __n) __THROW __nonnull ((1, 2));  
  58. /* 比较S1和S2 */  
  59. extern int strcmp (__const char *__s1, __const char *__s2)  
  60.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  61. /* 比较S1和S2的前N个字符 */  
  62. extern int strncmp (__const char *__s1, __const char *__s2, size_t __n)  
  63.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  64. /* 比较S1和S2对照后的形式(即按特定区域设置来进行字符排序) */  
  65. extern int strcoll (__const char *__s1, __const char *__s2)  
  66.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  67. /* 对SRC作转换并放到DEST的前N个字节中 */  
  68. extern size_t strxfrm (char *__restrict __dest,  
  69.                __const char *__restrict __src, size_t __n)  
  70.      __THROW __nonnull ((2));  
  71. __END_NAMESPACE_STD  
  72. #ifdef __USE_GNU  
  73. /* 下面的函数与上面的两个等价,但它们带一个额外的区域设置参数,用于设置字符对照规则。 
  74.     这是非标准的函数,但是在不久之后有可能会被标准化 */  
  75. # include <xlocale.h>  
  76. /* 使用L中的规则来比较S1和S2对照后的形式 */  
  77. extern int strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l)  
  78.      __THROW __attribute_pure__ __nonnull ((1, 2, 3));  
  79. /* 对SRC作转换并放到DEST的前N个字节中 */  
  80. extern size_t strxfrm_l (char *__dest, __const char *__src, size_t __n,  
  81.              __locale_t __l) __THROW __nonnull ((2, 4));  
  82. #endif  
  83. #if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED  
  84. /* 复制S,返回一个相同的副本 */  
  85. extern char *strdup (__const char *__s)  
  86.      __THROW __attribute_malloc__ __nonnull ((1));  
  87. #endif  
  88. /* 返回STRING的前N个字节的副本。即使STRING[N]前面没有出现终止符, 
  89.     结果字符串也会被终止 */  
  90. #if defined __USE_GNU  
  91. extern char *strndup (__const char *__string, size_t __n)  
  92.      __THROW __attribute_malloc__ __nonnull ((1));  
  93. #endif  
  94. #if defined __USE_GNU && defined __GNUC__  
  95. /* 复制S,返回一个相同的副本 */  
  96. # define strdupa(s)                               /  
  97.   (__extension__                                  /  
  98.     ({                                        /  
  99.       __const char *__old = (s);                          /  
  100.       size_t __len = strlen (__old) + 1;                      /  
  101.       char *__new = (char *) __builtin_alloca (__len);                /  
  102.       (char *) memcpy (__new, __old, __len);                      /  
  103.     }))  
  104. /* 返回字符串前N个字节的副本 */  
  105. # define strndupa(s, n)                               /  
  106.   (__extension__                                  /  
  107.     ({                                        /  
  108.       __const char *__old = (s);                          /  
  109.       size_t __len = strnlen (__old, (n));                    /  
  110.       char *__new = (char *) __builtin_alloca (__len + 1);            /  
  111.       __new[__len] = '/0';                            /  
  112.       (char *) memcpy (__new, __old, __len);                      /  
  113.     }))  
  114. #endif  
  115. __BEGIN_NAMESPACE_STD  
  116. /* 在S中搜索C的第一次出现 */  
  117. extern char *strchr (__const char *__s, int __c)  
  118.      __THROW __attribute_pure__ __nonnull ((1));  
  119. /* 在S中搜索C的最后一次出现  */  
  120. extern char *strrchr (__const char *__s, int __c)  
  121.      __THROW __attribute_pure__ __nonnull ((1));  
  122. __END_NAMESPACE_STD  
  123. #ifdef __USE_GNU  
  124. /* 这个函数与“strchr”类似,但如果在S中没有找到C,则它返回一个指向NUL终止符的指针 */  
  125. extern char *strchrnul (__const char *__s, int __c)  
  126.      __THROW __attribute_pure__ __nonnull ((1));  
  127. #endif  
  128. __BEGIN_NAMESPACE_STD  
  129. /* 返回S中的第一个子串长度,这个子串的所有字符都不在REJECT中 */  
  130. extern size_t strcspn (__const char *__s, __const char *__reject)  
  131.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  132. /* 返回S中的第一个子串长度,这个子串的所有字符都在ACCEPT中 */  
  133. extern size_t strspn (__const char *__s, __const char *__accept)  
  134.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  135. /* 返回S中的第一个在ACCEPT中出现的字符指针 */  
  136. extern char *strpbrk (__const char *__s, __const char *__accept)  
  137.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  138. /* 查找字符串NEEDLE在HAYSTACK中第一次出现  */  
  139. extern char *strstr (__const char *__haystack, __const char *__needle)  
  140.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  141. /* 用DELIM中的字符作为分隔符把S解析成多个记号 */  
  142. extern char *strtok (char *__restrict __s, __const char *__restrict __delim)  
  143.      __THROW __nonnull ((2));  
  144. __END_NAMESPACE_STD  
  145. /* 用DELIM中的字符作为分隔符把S分解为多个记号,上一次调用的信息存储在SAVE_PTR中 */  
  146. extern char *__strtok_r (char *__restrict __s,  
  147.              __const char *__restrict __delim,  
  148.              char **__restrict __save_ptr)  
  149.      __THROW __nonnull ((2, 3));  
  150. #if defined __USE_POSIX || defined __USE_MISC  
  151. extern char *strtok_r (char *__restrict __s, __const char *__restrict __delim,  
  152.                char **__restrict __save_ptr)  
  153.      __THROW __nonnull ((2, 3));  
  154. #endif  
  155. #ifdef __USE_GNU  
  156. /* 与“strstr”类似,但这个函数忽略字符串的大小写 */  
  157. extern char *strcasestr (__const char *__haystack, __const char *__needle)  
  158.      __THROW __attribute_pure__ __nonnull ((1, 2));  
  159. #endif  
  160. #ifdef __USE_GNU  
  161. /* 在HAYSTACK中查找NEEDLE的第一次出现。NEEDLE为NEEDLEN个字节长, 
  162.     HAYSTACK为HAYSTACKLEN个字节长 */  
  163. extern void *memmem (__const void *__haystack, size_t __haystacklen,  
  164.              __const void *__needle, size_t __needlelen)  
  165.      __THROW __attribute_pure__ __nonnull ((1, 3));  
  166. /* 将SRC的N个字节复制到DEST,返回最后一个写入字节后面位置的指针 */  
  167. extern void *__mempcpy (void *__restrict __dest,  
  168.             __const void *__restrict __src, size_t __n)  
  169.      __THROW __nonnull ((1, 2));  
  170. extern void *mempcpy (void *__restrict __dest,  
  171.               __const void *__restrict __src, size_t __n)  
  172.      __THROW __nonnull ((1, 2));  
  173. #endif  
  174. __BEGIN_NAMESPACE_STD  
  175. /* 返回S的长度 */  
  176. extern size_t strlen (__const char *__s)  
  177.      __THROW __attribute_pure__ __nonnull ((1));  
  178. __END_NAMESPACE_STD  
  179. #ifdef  __USE_GNU  
  180. /* 查找STRING的长度,但只扫描前MAXLEN个字符,如果其中没有发现'/0'终止符,则返回MAXLEN */  
  181. extern size_t strnlen (__const char *__string, size_t __maxlen)  
  182.      __THROW __attribute_pure__ __nonnull ((1));  
  183. #endif  
  184. __BEGIN_NAMESPACE_STD  
  185. /* 返回对错误码ERRNUM的字符串描述  */  
  186. extern char *strerror (int __errnum) __THROW;  
  187. __END_NAMESPACE_STD  
  188. /* 下面都是非标准扩展或内部使用的函数 */  
  189. __END_DECLS  
  190. #endif /* string.h  */  

    1、字符串连接strcat,strncat,wcscat,wcsncat:将字符串src(或其前n个字符)连接到dest,后面两个是宽字符版本。

 

 

[cpp] view plaincopy
  1. /* strcat.c:strcat函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h> /* 非标准头文件,定义了reg_char类型 */  
  4. #undef strcat  
  5. /* 将字符串SRC连接到DEST */  
  6. char *  
  7. strcat (dest, src)  
  8.      char *dest;  
  9.      const char *src;  
  10. {  
  11.   char *s1 = dest;  
  12.   const char *s2 = src;  
  13.   reg_char c; /* reg_char在memcopy.h中定义,就是char类型,它表示c存储在register中 */  
  14.     
  15.   do    /* 让s1指向dest的终止位置,即首个'/0'的下一位置  */  
  16.     c = *s1++;  
  17.   while (c != '/0');  
  18.   s1 -= 2; /* 让s1指向dest中的终止符'/0'的前一个位置,这样就可以进行连接操作了 */  
  19.   do     /* 做连接操作 */  
  20.     {  
  21.       c = *s2++;  
  22.       *++s1 = c;  
  23.     }  
  24.   while (c != '/0');  
  25.   return dest;  
  26. }  
  27. libc_hidden_builtin_def (strcat)  

 

 

[cpp] view plaincopy
  1. /* strncat.c:strncat函数的实现 */  
  2. #include <string.h>  
  3. #ifdef _LIBC  
  4. # include <memcopy.h> /* 非标准头文件,定义了reg_char类型,就是char类型 */  
  5. #else  
  6. typedef char reg_char;  
  7. #endif  
  8. #undef strncat  
  9. /* 将s2的前n个字符连接到s1,若s2不足n个字符,则连接完s2(包括终止符)后 
  10.     就返回 */  
  11. char *  
  12. strncat (s1, s2, n)  
  13.      char *s1;  
  14.      const char *s2;  
  15.      size_t n;  
  16. {  
  17.   reg_char c;  
  18.   char *s = s1;  
  19.   do  /* 让s1指向dest的终止位置,即首个'/0'的下一位置  */  
  20.     c = *s1++;  
  21.   while (c != '/0');  
  22.   s1 -= 2; /* 让s1指向dest中的终止符'/0'的前一个位置,这样就可以进行连接操作了 */  
  23.   if (n >= 4)      /* 做连接操作,每4个字符作为一组来进行连接 */  
  24.     {  
  25.       size_t n4 = n >> 2; /* 让n除以4,计算出循环次数 */  
  26.       do  
  27.     {  
  28.       c = *s2++;     /* 每次循环都要连接4个字符,总共连接了4*n4个字符 */  
  29.       *++s1 = c;  
  30.       if (c == '/0'/* 在连接时,每当遇到'/0',连接操作就停止,并返回目标串 */  
  31.         return s;  
  32.       c = *s2++;  
  33.       *++s1 = c;  
  34.       if (c == '/0')  
  35.         return s;  
  36.       c = *s2++;  
  37.       *++s1 = c;  
  38.       if (c == '/0')  
  39.         return s;  
  40.       c = *s2++;  
  41.       *++s1 = c;  
  42.       if (c == '/0')  
  43.         return s;  
  44.     } while (--n4 > 0);  
  45.       n &= 3; /* 求出n除以4的余数 */  
  46.     }  
  47.   while (n > 0) /* 对剩下的几个字符(最多3个)进行连接 */  
  48.     {  
  49.       c = *s2++;  
  50.       *++s1 = c;  
  51.       if (c == '/0')  
  52.     return s;  
  53.       n--;  
  54.     }  
  55.   if (c != '/0')  /* 如果末尾不是终止符,则要补上一个终止符 */  
  56.     *++s1 = '/0';  
  57.   return s;  
  58. }  

 

    解释:
    (1)strcat基本思想:把指针移到dest的终止符'/0'的前一个位置,然后扫描src的每个字符并连接到dest的后面。
    (2)strncat基本思想:为减少扫描的循环次数以提高效率,对src的每4个字符作为一组来进行连接,让n除以4,计算出循环次数n4。每次循环都要连接4个字符,总共连接了4*n4个字符,最后对剩下的几个字符(最多3个)进行连接。若src的第n个字符不是终止符'/0',则连接的末尾还要补上一个终止符。
    2、字符串比较strcmp,strncmp,wcscmp,wcsncmp:按照字典顺序比较两个字符串(或其前n个字符)的大小。

 

[cpp] view plaincopy
  1. /* strcmp.c:strcmp函数的实现  */  
  2. #include <string.h>  
  3. #include <memcopy.h>  /* 非标准头文件,定义了reg_char类型 */  
  4. #undef strcmp  
  5. /* 比较S1和S2,小于返回小于0的数,等于时返回0,大于时返回大于0的数 */  
  6. int  
  7. strcmp (p1, p2)  
  8.      const char *p1;  
  9.      const char *p2;  
  10. {  
  11.   register const unsigned char *s1 = (const unsigned char *) p1;  
  12.   register const unsigned char *s2 = (const unsigned char *) p2;  
  13.   unsigned reg_char c1, c2;  
  14.   do  
  15.     {  
  16.       c1 = (unsigned char) *s1++;  
  17.       c2 = (unsigned char) *s2++;  
  18.       if (c1 == '/0')  /* 若s1终止,则比较结束,返回相应差值 */  
  19.     return c1 - c2;  
  20.     }  
  21.   while (c1 == c2); /* 做相等比较,直到不相等时退出循环 */  
  22.   return c1 - c2;  /* 返回相应的差值 */  
  23. }  
  24. libc_hidden_builtin_def (strcmp)  

 

 

[cpp] view plaincopy
  1. /* strncmp.c:strncmp函数的实现 */  
  2. #include <string.h>  
  3. #include <memcopy.h>  
  4. #undef strncmp  
  5. /* 比较s1和s2的前n个字符,不足n个字符时使用整个字符串, 
  6.     小于返回小于0的数,等于时返回0,大于时返回大于0的数 */  
  7. int  
  8. strncmp (s1, s2, n)  
  9.      const char *s1;  
  10.      const char *s2;  
  11.      size_t n;  
  12. {  
  13.   unsigned reg_char c1 = '/0';  
  14.   unsigned reg_char c2 = '/0';  
  15.   if (n >= 4)      /* 做比较操作,每4个字符作为一组来进行比较 */  
  16.     {  
  17.       size_t n4 = n >> 2;  /* 做比较操作,每4个字符作为比较来进行连接 */  
  18.       do  
  19.     {  
  20.       c1 = (unsigned char) *s1++; /* 每次循环都要比较4个字符,总共比较了4*n4个字符 */  
  21.       c2 = (unsigned char) *s2++;  
  22.       if (c1 == '/0' || c1 != c2)/* 每当遇到s1终止或c1!=c2,比较操作就结束,并返回相应差值 */  
  23.         return c1 - c2;  
  24.       c1 = (unsigned char) *s1++;  
  25.       c2 = (unsigned char) *s2++;  
  26.       if (c1 == '/0' || c1 != c2)  
  27.         return c1 - c2;  
  28.       c1 = (unsigned char) *s1++;  
  29.       c2 = (unsigned char) *s2++;  
  30.       if (c1 == '/0' || c1 != c2)  
  31.         return c1 - c2;  
  32.       c1 = (unsigned char) *s1++;  
  33.       c2 = (unsigned char) *s2++;  
  34.       if (c1 == '/0' || c1 != c2)  
  35.         return c1 - c2;  
  36.     } while (--n4 > 0);  
  37.       n &= 3;  /* 求出n除以4的余数 */  
  38.     }  
  39.   while (n > 0) /* 对剩下的几个字符(最多3个)进行比较 */  
  40.     {  
  41.       c1 = (unsigned char) *s1++;  
  42.       c2 = (unsigned char) *s2++;  
  43.       if (c1 == '/0' || c1 != c2)  /* 若s1终止或c1!=c2,则比较结束,返回相应差值 */  
  44.     return c1 - c2;  
  45.       n--;  
  46.     }  
  47.   return c1 - c2;  /* 返回相应差值 */  
  48. }  
  49. libc_hidden_builtin_def (strncmp)  

 

    解释:
    (1)strcmp基本思想:扫描两个串,并对字符作相等比较,直到不相等时退出循环,返回这两个字符的差值。
    (2)strncmp基本思想:做比较操作,每4个字符作为一组来进行比较,以提高效率。扫描两个串,每次循环时连续比较4个字符,直到比较完前n个字符。

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