原文出自:http://blog.youkuaiyun.com/zhoudaxia/article/details/4641693
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等。
- /* ISO C99 Standard: 7.21 字符串处理 <string.h> */
- #ifndef _STRING_H
- #define _STRING_H 1
- #include <features.h> /* 非标准头文件,定义了一些编译选项 */
- __BEGIN_DECLS
- /* 从<stddef.h>中获得size_t和NULL */
- #define __need_size_t
- #define __need_NULL
- #include <stddef.h>
- __BEGIN_NAMESPACE_STD
- /* 从SRC中复制N个字节的内容到DEST中 */
- extern void *memcpy (void *__restrict __dest,
- __const void *__restrict __src, size_t __n)
- __THROW __nonnull ((1, 2));
- /* 从SRC中复制N个字节的内容到DEST中,保证对重叠字符串(即SRC与DEST共用存储空间)有正确的行为 */
- extern void *memmove (void *__dest, __const void *__src, size_t __n)
- __THROW __nonnull ((1, 2));
- __END_NAMESPACE_STD
- /* 从SRC中复制不超过N个字节的内容到DEST中,当遇到字符C时便停止,返回DEST中C的拷贝后面的字符指针。
- 如果在SRC的前面N个字节中没有发现字符C,则返回NULL */
- #if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN
- extern void *memccpy (void *__restrict __dest, __const void *__restrict __src,
- int __c, size_t __n)
- __THROW __nonnull ((1, 2));
- #endif /* SVID. */
- __BEGIN_NAMESPACE_STD
- /* 把S的前N个字节的内容设置为C */
- extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
- /* 比较S1和S2的前n字节的内容 */
- extern int memcmp (__const void *__s1, __const void *__s2, size_t __n)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 在S的前N个字节中搜索C的第一次出现 */
- extern void *memchr (__const void *__s, int __c, size_t __n)
- __THROW __attribute_pure__ __nonnull ((1));
- __END_NAMESPACE_STD
- #ifdef __USE_GNU
- /* 在S中搜索C,这与“memchr”类似,但这里没有长度的限制 */
- extern void *rawmemchr (__const void *__s, int __c)
- __THROW __attribute_pure__ __nonnull ((1));
- /* 在S的前N个字节中搜索C的最后一次出现 */
- extern void *memrchr (__const void *__s, int __c, size_t __n)
- __THROW __attribute_pure__ __nonnull ((1));
- #endif
- __BEGIN_NAMESPACE_STD
- /* 将SRC复制到DEST中 */
- extern char *strcpy (char *__restrict __dest, __const char *__restrict __src)
- __THROW __nonnull ((1, 2));
- /* 将SRC的前N个字符复制到DEST */
- extern char *strncpy (char *__restrict __dest,
- __const char *__restrict __src, size_t __n)
- __THROW __nonnull ((1, 2));
- /* 将SRC追加到DEST */
- extern char *strcat (char *__restrict __dest, __const char *__restrict __src)
- __THROW __nonnull ((1, 2));
- /* 将SRC的前N个字符追加到DEST */
- extern char *strncat (char *__restrict __dest, __const char *__restrict __src,
- size_t __n) __THROW __nonnull ((1, 2));
- /* 比较S1和S2 */
- extern int strcmp (__const char *__s1, __const char *__s2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 比较S1和S2的前N个字符 */
- extern int strncmp (__const char *__s1, __const char *__s2, size_t __n)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 比较S1和S2对照后的形式(即按特定区域设置来进行字符排序) */
- extern int strcoll (__const char *__s1, __const char *__s2)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 对SRC作转换并放到DEST的前N个字节中 */
- extern size_t strxfrm (char *__restrict __dest,
- __const char *__restrict __src, size_t __n)
- __THROW __nonnull ((2));
- __END_NAMESPACE_STD
- #ifdef __USE_GNU
- /* 下面的函数与上面的两个等价,但它们带一个额外的区域设置参数,用于设置字符对照规则。
- 这是非标准的函数,但是在不久之后有可能会被标准化 */
- # include <xlocale.h>
- /* 使用L中的规则来比较S1和S2对照后的形式 */
- extern int strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l)
- __THROW __attribute_pure__ __nonnull ((1, 2, 3));
- /* 对SRC作转换并放到DEST的前N个字节中 */
- extern size_t strxfrm_l (char *__dest, __const char *__src, size_t __n,
- __locale_t __l) __THROW __nonnull ((2, 4));
- #endif
- #if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED
- /* 复制S,返回一个相同的副本 */
- extern char *strdup (__const char *__s)
- __THROW __attribute_malloc__ __nonnull ((1));
- #endif
- /* 返回STRING的前N个字节的副本。即使STRING[N]前面没有出现终止符,
- 结果字符串也会被终止 */
- #if defined __USE_GNU
- extern char *strndup (__const char *__string, size_t __n)
- __THROW __attribute_malloc__ __nonnull ((1));
- #endif
- #if defined __USE_GNU && defined __GNUC__
- /* 复制S,返回一个相同的副本 */
- # define strdupa(s) /
- (__extension__ /
- ({ /
- __const char *__old = (s); /
- size_t __len = strlen (__old) + 1; /
- char *__new = (char *) __builtin_alloca (__len); /
- (char *) memcpy (__new, __old, __len); /
- }))
- /* 返回字符串前N个字节的副本 */
- # define strndupa(s, n) /
- (__extension__ /
- ({ /
- __const char *__old = (s); /
- size_t __len = strnlen (__old, (n)); /
- char *__new = (char *) __builtin_alloca (__len + 1); /
- __new[__len] = '/0'; /
- (char *) memcpy (__new, __old, __len); /
- }))
- #endif
- __BEGIN_NAMESPACE_STD
- /* 在S中搜索C的第一次出现 */
- extern char *strchr (__const char *__s, int __c)
- __THROW __attribute_pure__ __nonnull ((1));
- /* 在S中搜索C的最后一次出现 */
- extern char *strrchr (__const char *__s, int __c)
- __THROW __attribute_pure__ __nonnull ((1));
- __END_NAMESPACE_STD
- #ifdef __USE_GNU
- /* 这个函数与“strchr”类似,但如果在S中没有找到C,则它返回一个指向NUL终止符的指针 */
- extern char *strchrnul (__const char *__s, int __c)
- __THROW __attribute_pure__ __nonnull ((1));
- #endif
- __BEGIN_NAMESPACE_STD
- /* 返回S中的第一个子串长度,这个子串的所有字符都不在REJECT中 */
- extern size_t strcspn (__const char *__s, __const char *__reject)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 返回S中的第一个子串长度,这个子串的所有字符都在ACCEPT中 */
- extern size_t strspn (__const char *__s, __const char *__accept)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 返回S中的第一个在ACCEPT中出现的字符指针 */
- extern char *strpbrk (__const char *__s, __const char *__accept)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 查找字符串NEEDLE在HAYSTACK中第一次出现 */
- extern char *strstr (__const char *__haystack, __const char *__needle)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- /* 用DELIM中的字符作为分隔符把S解析成多个记号 */
- extern char *strtok (char *__restrict __s, __const char *__restrict __delim)
- __THROW __nonnull ((2));
- __END_NAMESPACE_STD
- /* 用DELIM中的字符作为分隔符把S分解为多个记号,上一次调用的信息存储在SAVE_PTR中 */
- extern char *__strtok_r (char *__restrict __s,
- __const char *__restrict __delim,
- char **__restrict __save_ptr)
- __THROW __nonnull ((2, 3));
- #if defined __USE_POSIX || defined __USE_MISC
- extern char *strtok_r (char *__restrict __s, __const char *__restrict __delim,
- char **__restrict __save_ptr)
- __THROW __nonnull ((2, 3));
- #endif
- #ifdef __USE_GNU
- /* 与“strstr”类似,但这个函数忽略字符串的大小写 */
- extern char *strcasestr (__const char *__haystack, __const char *__needle)
- __THROW __attribute_pure__ __nonnull ((1, 2));
- #endif
- #ifdef __USE_GNU
- /* 在HAYSTACK中查找NEEDLE的第一次出现。NEEDLE为NEEDLEN个字节长,
- HAYSTACK为HAYSTACKLEN个字节长 */
- extern void *memmem (__const void *__haystack, size_t __haystacklen,
- __const void *__needle, size_t __needlelen)
- __THROW __attribute_pure__ __nonnull ((1, 3));
- /* 将SRC的N个字节复制到DEST,返回最后一个写入字节后面位置的指针 */
- extern void *__mempcpy (void *__restrict __dest,
- __const void *__restrict __src, size_t __n)
- __THROW __nonnull ((1, 2));
- extern void *mempcpy (void *__restrict __dest,
- __const void *__restrict __src, size_t __n)
- __THROW __nonnull ((1, 2));
- #endif
- __BEGIN_NAMESPACE_STD
- /* 返回S的长度 */
- extern size_t strlen (__const char *__s)
- __THROW __attribute_pure__ __nonnull ((1));
- __END_NAMESPACE_STD
- #ifdef __USE_GNU
- /* 查找STRING的长度,但只扫描前MAXLEN个字符,如果其中没有发现'/0'终止符,则返回MAXLEN */
- extern size_t strnlen (__const char *__string, size_t __maxlen)
- __THROW __attribute_pure__ __nonnull ((1));
- #endif
- __BEGIN_NAMESPACE_STD
- /* 返回对错误码ERRNUM的字符串描述 */
- extern char *strerror (int __errnum) __THROW;
- __END_NAMESPACE_STD
- /* 下面都是非标准扩展或内部使用的函数 */
- __END_DECLS
- #endif /* string.h */
1、字符串连接strcat,strncat,wcscat,wcsncat:将字符串src(或其前n个字符)连接到dest,后面两个是宽字符版本。
- /* strcat.c:strcat函数的实现 */
- #include <string.h>
- #include <memcopy.h> /* 非标准头文件,定义了reg_char类型 */
- #undef strcat
- /* 将字符串SRC连接到DEST */
- char *
- strcat (dest, src)
- char *dest;
- const char *src;
- {
- char *s1 = dest;
- const char *s2 = src;
- reg_char c; /* reg_char在memcopy.h中定义,就是char类型,它表示c存储在register中 */
- do /* 让s1指向dest的终止位置,即首个'/0'的下一位置 */
- c = *s1++;
- while (c != '/0');
- s1 -= 2; /* 让s1指向dest中的终止符'/0'的前一个位置,这样就可以进行连接操作了 */
- do /* 做连接操作 */
- {
- c = *s2++;
- *++s1 = c;
- }
- while (c != '/0');
- return dest;
- }
- libc_hidden_builtin_def (strcat)
- /* strncat.c:strncat函数的实现 */
- #include <string.h>
- #ifdef _LIBC
- # include <memcopy.h> /* 非标准头文件,定义了reg_char类型,就是char类型 */
- #else
- typedef char reg_char;
- #endif
- #undef strncat
- /* 将s2的前n个字符连接到s1,若s2不足n个字符,则连接完s2(包括终止符)后
- 就返回 */
- char *
- strncat (s1, s2, n)
- char *s1;
- const char *s2;
- size_t n;
- {
- reg_char c;
- char *s = s1;
- do /* 让s1指向dest的终止位置,即首个'/0'的下一位置 */
- c = *s1++;
- while (c != '/0');
- s1 -= 2; /* 让s1指向dest中的终止符'/0'的前一个位置,这样就可以进行连接操作了 */
- if (n >= 4) /* 做连接操作,每4个字符作为一组来进行连接 */
- {
- size_t n4 = n >> 2; /* 让n除以4,计算出循环次数 */
- do
- {
- c = *s2++; /* 每次循环都要连接4个字符,总共连接了4*n4个字符 */
- *++s1 = c;
- if (c == '/0') /* 在连接时,每当遇到'/0',连接操作就停止,并返回目标串 */
- return s;
- c = *s2++;
- *++s1 = c;
- if (c == '/0')
- return s;
- c = *s2++;
- *++s1 = c;
- if (c == '/0')
- return s;
- c = *s2++;
- *++s1 = c;
- if (c == '/0')
- return s;
- } while (--n4 > 0);
- n &= 3; /* 求出n除以4的余数 */
- }
- while (n > 0) /* 对剩下的几个字符(最多3个)进行连接 */
- {
- c = *s2++;
- *++s1 = c;
- if (c == '/0')
- return s;
- n--;
- }
- if (c != '/0') /* 如果末尾不是终止符,则要补上一个终止符 */
- *++s1 = '/0';
- return s;
- }
解释:
(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个字符)的大小。
- /* strcmp.c:strcmp函数的实现 */
- #include <string.h>
- #include <memcopy.h> /* 非标准头文件,定义了reg_char类型 */
- #undef strcmp
- /* 比较S1和S2,小于返回小于0的数,等于时返回0,大于时返回大于0的数 */
- int
- strcmp (p1, p2)
- const char *p1;
- const char *p2;
- {
- register const unsigned char *s1 = (const unsigned char *) p1;
- register const unsigned char *s2 = (const unsigned char *) p2;
- unsigned reg_char c1, c2;
- do
- {
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '/0') /* 若s1终止,则比较结束,返回相应差值 */
- return c1 - c2;
- }
- while (c1 == c2); /* 做相等比较,直到不相等时退出循环 */
- return c1 - c2; /* 返回相应的差值 */
- }
- libc_hidden_builtin_def (strcmp)
- /* strncmp.c:strncmp函数的实现 */
- #include <string.h>
- #include <memcopy.h>
- #undef strncmp
- /* 比较s1和s2的前n个字符,不足n个字符时使用整个字符串,
- 小于返回小于0的数,等于时返回0,大于时返回大于0的数 */
- int
- strncmp (s1, s2, n)
- const char *s1;
- const char *s2;
- size_t n;
- {
- unsigned reg_char c1 = '/0';
- unsigned reg_char c2 = '/0';
- if (n >= 4) /* 做比较操作,每4个字符作为一组来进行比较 */
- {
- size_t n4 = n >> 2; /* 做比较操作,每4个字符作为比较来进行连接 */
- do
- {
- c1 = (unsigned char) *s1++; /* 每次循环都要比较4个字符,总共比较了4*n4个字符 */
- c2 = (unsigned char) *s2++;
- if (c1 == '/0' || c1 != c2)/* 每当遇到s1终止或c1!=c2,比较操作就结束,并返回相应差值 */
- return c1 - c2;
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '/0' || c1 != c2)
- return c1 - c2;
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '/0' || c1 != c2)
- return c1 - c2;
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '/0' || c1 != c2)
- return c1 - c2;
- } while (--n4 > 0);
- n &= 3; /* 求出n除以4的余数 */
- }
- while (n > 0) /* 对剩下的几个字符(最多3个)进行比较 */
- {
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '/0' || c1 != c2) /* 若s1终止或c1!=c2,则比较结束,返回相应差值 */
- return c1 - c2;
- n--;
- }
- return c1 - c2; /* 返回相应差值 */
- }
- libc_hidden_builtin_def (strncmp)
解释:
(1)strcmp基本思想:扫描两个串,并对字符作相等比较,直到不相等时退出循环,返回这两个字符的差值。
(2)strncmp基本思想:做比较操作,每4个字符作为一组来进行比较,以提高效率。扫描两个串,每次循环时连续比较4个字符,直到比较完前n个字符。
本文详细介绍了C库中的字符串处理函数,包括连接、比较、复制等常见操作,以及内存处理函数如复制、移动等。通过示例代码解析了`strcat`、`strncat`、`strcmp`等函数的实现原理,展示了如何高效地进行字符串操作。
1214

被折叠的 条评论
为什么被折叠?



