C语言 -- string.h中函数功能详解与手动实现 - 03(常用函数memchr、strchr、strstr、strspn、strlen、strnlen...)

  • 本文中所有设计的代码均通过测试,并且在功能性方面均实现应有的功能。
  • 如果你也对此感兴趣、也想测试源码的话,可以私聊我,非常欢迎一起探讨学习。
  • 由于时间、水平、精力有限,文中难免会出现不准确、甚至错误的地方,也很欢迎大佬看见的话批评指正。
摘要

  一般系统中提供一个标准的C库 string.h ,用于操作各种操作字符串( strxxx )、内存( memxxx )的库函数。作为 C标准库 的一部分,它们被强制要求可以在任何支持 C语言 的平台上运行。 不管是在面试中还是平时的工作中,对 string.h 文件中的大部分的函数的都有涉及,并且会经常遇到手撕某个或者某几个库函数的题目,其重要程度可想而知。

  续接上文:

  C语言 – string.h中函数功能详解与手动实现 - 01(常用函数memset、memcmp、strcmp、strncmp …)

  C语言 – string.h中函数功能详解与手动实现 - 02(常用函数memcpy、memmove、strcpy、strdup、strcat、strtok…)

3.9、查询类型 — 函数功能详细说明 :在内存空间/字符串查找特定字符(串)

void *memchr(const void *s, int c, size_t n);
	功能:扫描指针 s 指向的内存区域的前 n 个字节,找到第一次出现字符 c 的位置
	返回:1、如果成功找到字符c,返回指向字符 c 的指针
		 2、如果在指定区域中没有找到字符 c,则返回 NULL
	说明:1、当第一次遇到字符 c 时即停止查找
		 2、c 和 s 指向的内存区域的字节都被解释为无符号字符
		 3、需要保证 n 的有效值与 s 指向内存区域大小的匹配性
			如果 n 大于 s 指向内存区域大小,则对于未找到 c 的情况,返回值的将不可控
void *memrchr(const void *s, int c, size_t n);
	功能:扫描指针 s 指向的内存区域末尾的后 n 个字节,找到最后一次出现字符 c 的位置
	返回:1、如果成功找到字符c,返回指向字符 c 的指针
		 2、如果在指定区域中没有找到字符 c,则返回 NULL
	说明:1、当最后一次遇到字符 c 时即停止查找
		 2、c 和 s 指向的内存区域的字节都被解释为无符号字符
		 3、为GNU的扩展,不是C语言的一部分,最早出现在glibc的2.2版中
		 4、需要 #define _GNU_SOURCE
void *rawmemchr(const void *s, int c);
	功能:扫描指针 s 指向的内存区域出现字符 c 的位置
	返回:1、如果成功找到字符c,返回指向字符 c 的指针
		 2、如果在指定区域中没有找到字符,则结果是不可预测的
	说明:1、与函数 memchr 类似,可理解为函数 memchr()的优化版本
		 2、假设确定在 s 所指区域中必须包含至少一个字符 c,因此对c执行优化搜索
		 3、为GNU的扩展,不是C语言的一部分,最早出现在glibc的2.1版中
		 4、需要 #define _GNU_SOURCE
		 5、快速查找字符串的终止空字节的方法 char *p = rawmemchr(s, '\0');
char *strchr(const char *s, int c);
    功能:查找字符串 s 中首次出现字符 c 的位置
	返回:1、如果找到 c,则返回首次出现 c 的位置的指针
		 2、如果 s 中不存在 c,则返回 NULL。
	说明:1、终止的空字节被认为是字符串的一部分,因此如果 c 被指定为'\0',则将返回指向终止符的指针
		 2、函数不适用于宽字符或多字节字符
		 3、c 和 s 指向的字符串的字节都被解释为无符号字符(unsigned char4、如果 s 指向的字符串中不包含'\0',则将发生异常
char *strrchr(const char *s, int c);	
	功能:查找字符串 s 中最后一次出现字符 c 的位置
    返回:1、如果找到字符 c, 则返回最后一次出现 c 的位置的指针
		 2、如果 s 中不存在 c, 则返回NULL
	说明:与 strchr 一致
char *strstr(const char *haystack, const char *needle);
    功能:从字符串 haystack 中寻找 needle 所指子字符串第一次出现的位置(不比较结束符 '\0')。
    返回:1、如果匹配,则返回指向第一次出现 needle 所指子字符串位置的指针,
		 2、如果没找,则返回 NULL。
	说明:1、如果子字符串 needle 为空(空字符串),则函数返回 haystack
		 2、如果子字符串 needle 长度为一个字节,使用与 strchr 类似
char *strcasestr(const char *haystack, const char *needle);
	功能:从字符串 haystack 中寻找 needle 所指子字符串第一次出现的位置(不比较结束符 '\0')。
    返回:1、如果匹配,则返回指向第一次出现 needle 所指子字符串位置的指针,
		 2、如果没找,则返回 NULL。
	说明:1、如果子字符串 needle 为空(空字符串),则函数返回 haystack
		 2、如果子字符串 needle 长度为一个字节,使用与 strchr 类似
		 3、与strstr函数功能一致,唯一区别为此函数在匹配过程中不区分字符的大小写
		 4、是一个非标准扩展,需要 #define _GNU_SOURCE 
char *strpbrk(const char *s, const char *accept);
	功能:在字符串 s 中寻找字符串 accept 中任何一个字符相匹配的第一个字符的位置(不包含 '\0')
    返回:1、如果匹配成功(至少一个字符),则返回指向 s 中第一个相匹配的字符的指针
		 2、如果没有匹配字符,则返回 NULL。
	说明:1、如果 accept 为空字符串,则返回 NULL
		 2、如果在 s 字符串中存在完全匹配的 accept,则返回指向完全配的字符串的位置指针,
		 	而不是匹配的第一个字符(或其他字符)
size_t strspn(const char *s, const char *accept);
	功能:计算在字符串 s 中,有多少个连续的字符都属于字符串 accept
	返回:从字符串 s 开头计算与字符串 accept 完全一致的字符的个数
	说明:1、如果字符串 s 的第一个字符不属于 accept,那么返回 0
		 2、如果字符串 s 所指向的字符串都属于 accept,那么返回字符串 s 的长度
		 3、如果字符串 s 开头连续有 n 个字符都属于字符串 accept,则返回 n
		 4、如果 accept 为空字符串,则返回 0
size_t strcspn(const char *s, const char *reject);
	功能:计算 reject 中某个字符在的 s 中第一个出现的位置
	返回:reject 中某个字符在的 s 中第一个出现的下标值 
	说明:1、如果 s 和 reject 的交集为空,也就是 reject 中任何一个字符在 s 中不存在,
			则返回 s 的字符串长度
		 2、如果 s 与 reject 的交集不为空,也就是 reject 与 s 中存在共同的字符,
			那么返回在 s 中从前到后首次出现 reject 的某个字符下标
		 3、如果 accept 为空字符串('\0'),则返回 0
		 

3.10、查询类型 — 函数功能测试与手动实现

3.10.1、memchr

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void *my_memchr(const void *s, int c, size_t n)
{
       const unsigned char *s_in = (unsigned char *)s;
       unsigned char c_in = (unsigned char)c;
       for (; n > 0; --n, ++s_in)
       {
              if (*s_in == c_in)
                     return (void *)s_in;
       }
       return NULL;
}

int main(int argc, const char **argv)
{
       const char *str = "I'm the test string";

       printf("Before memchr(t), str = %s, length = %ld\n", str, strlen(str));

       // memchr 测试
       char *ret = (char *)memchr(str, 't', strlen(str));
       printf("After  memchr(t), str = %s, length = %ld\n", str, strlen(str));
       printf("                  ret = %s\n ", ret);
       putchar(10);

       ret = (char *)memchr(str, ';', strlen(str));
       printf("After  memchr(;), str = %s, length = %ld\n", str, strlen(str));
       printf("                  ret = %s\n ", ret);
       putchar(10);

       // memchr n 远远大于 有效区域 测试,同时字符串中存在要查找的字符
       ret = (char *)memchr(str, 't', strlen(str) + 100000);
       printf("After  memchr(t,100000), str = %s, length = %ld\n", str, strlen(str));
       printf("                         ret = %s\n ", ret);
       putchar(10);

       // memchr n 远远大于 有效区域测试,同时有效字符串中不存在要查找的字符
       // 下面的测试结果不定,具体按运行结果为准
       ret = (char *)memchr(str, ';', strlen(str) + 1000000);
       printf("After  memchr(;,100000), str = %s, length = %ld\n", str, strlen(str));
       printf("                         ret = %s\n ", ret);
       putchar(10);

       // my_memchr 测试
       ret = (char *)my_memchr(str, 't', strlen(str));
       printf("After  my_memchr(t), str = %s, length = %ld\n", str, strlen(str));
       printf("                     ret = %s\n ", ret);
       putchar(10);

       ret = (char *)my_memchr(str, ';', strlen(str));
       printf("After  my_memchr(;), str = %s, length = %ld\n", str, strlen(str));
       printf("                     ret = %s\n ", ret);

       printf("\n\e[1;32msystem exited with return code %d\e[0m\n\n", 0);

       return 0;
}

  测试效果如下图所示。

3.10.2、strchr、strrchr

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *my_strchr(const char *s, int c)
{
    const unsigned char *s_in = (const unsigned char *)s;
    unsigned char c_in = (unsigned char)c;

    for (; *s_in != '\0'; ++s_in)
    {
        if (*s_in == c_in) return (char *)s_in;
    }
    return NULL;
}

char *my_strrchr(const char *s, int c)
{
    char *found = NULL, *p = NULL;

    if (c == '\0') return strchr(s, '\0');

    while ((p = strchr(s, c)) != NULL)
    {
        found = p;
        s = p + 1;
    }

    return (char *)found;
}

int main(int argc, const char **argv)
{
    char src[20];
    const char *str = "I'm the test string";

    /* strchr 测试 */
    // strchr 的正常测试 -- 找到 c
    printf("Before strchr(h), str = %s, length = %ld\n", str, strlen(str));
    char *ret = strchr(str, 'h');
    printf("After  strchr(h), str = %s, length = %ld\n", str, strlen(str));
    printf("                  ret = %s\n", ret);
    putchar(10);

    // strchr 的正常测试 -- 未找到 c
    ret = strchr(str, ';');
    printf("After  strchr(;), str = %s, length = %ld\n", str, strlen(str));
    printf("                  ret = %s\n", ret);
    putchar(10);

    memset(src, 'A', 20);
    src[10] = 'B';
    printf("Before strchr(B), str = %s, length = %ld\n", src, strlen(src));

    // strchr 不正常测试 -- 找到 c
    ret = strchr(src, 'B');
    printf("After  strchr(B), str = %s, length = %ld\n", str, strlen(str));
    printf("                  ret = %s\n", ret);
    putchar(10);

    // strchr 不正常测试 -- 未找到 c
    ret = strchr(src, 'C');
    printf("After  strchr(C), str = %s, length = %ld\n", str, strlen(str));
    printf("                  ret = %s\n", ret);
    putchar(10);

    /* my_strchr 测试 */
    // my_strchr 的正常测试 -- 找到 c
    ret = my_strchr(str, 'h');
    printf("After  my_strchr(h), str = %s, length = %ld\n", str, strlen(str));
    printf("                     ret = %s\n", ret);
    putchar(10);

    // strchr 的正常测试 -- 未找到 c
    ret = my_strchr(str, ';');
    printf("After  my_strchr(;), str = %s, length = %ld\n", str, strlen(str));
    printf("                     ret = %s\n", ret);
    putchar(10);

    /* strrchr 测试 */
    printf("Before strrchr(e), str = %s, length = %ld\n", str, strlen(str));
    ret = strrchr(str, 'e');
    printf("After  strrchr(e), str = %s, length = %ld\n", str, strlen(str));
    printf("                   ret = %s\n", ret);
    putchar(10);

    printf("Before strrchr(a), str = %s, length = %ld\n", str, strlen(str));
    ret = strrchr(str, 'a');
    printf("After  strrchr(a), str = %s, length = %ld\n", str, strlen(str));
    printf("                   ret = %s\n", ret);
    putchar(10);

    /* my_strrchr 测试 */
    printf("Before my_strrchr(e), str = %s, length = %ld\n", str, strlen(str));
    ret = my_strrchr(str, 'e');
    printf("After  my_strrchr(e), str = %s, length = %ld\n", str, strlen(str));
    printf("                      ret = %s\n", ret);
    putchar(10);

    printf("Before my_strrchr(a), str = %s, length = %ld\n", str, strlen(str));
    ret = my_strrchr(str, 'a');
    printf("After  my_strrchr(a), str = %s, length = %ld\n", str, strlen(str));
    printf("                      ret = %s\n", ret);

    printf("\n\e[1;32msystem exited with return code %d\e[0m\n\n", 0);

    return 0;
}

  测试效果如下图所示。

3.10.3、strspn、strcspn

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char **argv)
{
    char *s = "abcdefghABCDEFGH";
    int pos = 0;

    /* strspn 测试 */
    printf("Before strspn, s = %s, strlen(s) = %ld, accept = abcdefghABCDEFGH\n", s, strlen(s));
    pos = strspn(s, "abcdefghABCDEFGH");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    printf("Before strspn, s = %s, strlen(s) = %ld, accept = abcdefghABCDEFG\n", s, strlen(s));
    pos = strspn(s, "abcdefghABCDEFG");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    printf("Before strspn, s = %s, strlen(s) = %ld, accept = abcdCDEFG\n", s, strlen(s));
    pos = strspn(s, "abcdefghABCDEFG");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    printf("Before strspn, s = %s, strlen(s) = %ld, accept = bcdefghABCDEFGH\n", s, strlen(s));
    pos = strspn(s, "efghABC");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    printf("Before strspn, s = %s, strlen(s) = %ld, accept = sdef\n", s, strlen(s));
    pos = strspn(s, "sdef");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    printf("Before strspn, s = %s, strlen(s) = %ld, accept = ''\n", s, strlen(s));
    pos = strspn(s, "");
    printf("After  strspn, ret = %d\n", pos);
    putchar(10);

    /* strcspn 测试 */ 
    // 下标值
    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = abcdefghABCDEFGH\n", s, strlen(s));
    pos = strcspn(s, "abcdefghABCDEFGH");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = abcd\n", s, strlen(s));
    pos = strcspn(s, "abcd");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = bcd\n", s, strlen(s));
    pos = strcspn(s, "bcd");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = ABCD\n", s, strlen(s));
    pos = strcspn(s, "ABCD");
    printf("After  strcspn, ret = %d\n", pos);

    // abcdefghABCDEFGH
    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = abcdefgh\n", s, strlen(s));
    pos = strcspn(s, "abcdefgh");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = bcdefgha\n", s, strlen(s));
    pos = strcspn(s, "bcdefgha");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = cdefghb\n", s, strlen(s));
    pos = strcspn(s, "cdefghb");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = cdefghab\n", s, strlen(s));
    pos = strcspn(s, "cdefghab");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = fghde\n", s, strlen(s));
    pos = strcspn(s, "fghde");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = fgh\n", s, strlen(s));
    pos = strcspn(s, "fgh");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = H\n", s, strlen(s));
    pos = strcspn(s, "H");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = ''\n", s, strlen(s));
    pos = strcspn(s, "");
    printf("After  strcspn, ret = %d\n", pos);

    printf("Before strcspn, s = %s, strlen(s) = %ld, accept = lmjk\n", s, strlen(s));
    pos = strcspn(s, "lmjk");
    printf("After  strcspn, ret = %d\n", pos);

    printf("\n\e[1;32msystem exited with return code %d\e[0m\n\n", 0);

    return 0;
}

  测试效果如下图所示。

3.11、属性类型 — 函数功能详细说明 :计算字符串包含的字符个数/长度

size_t strlen(const char *s);
    功能:计算字符串 s 的长度,以'\0'判断结束,但是不包含'\0' 
    返回:返回字符串s的长度,不包括结束符’\0‘。
    说明:计算的是字符串的实际长度,遇到第一个'\0'结束。
			如果只定义没有给它赋初值或在有效空间内没有'\0'这个结果是不定的,会从首地址一直计算直到遇到'\0'停止
size_t strnlen(const char *s, size_t maxlen);
	功能:计算 s 指向的字符串中的字符个数,以'\0'判断结束但是不包含'\0'  
	返回:1、如果 s 指向字符串的长度小于 maxlen,则函数返回字符串长度
		 2、如果 s 指向字符串的长度大于 maxlen 或者 第一个 maxlen 字符中没有遇到'\0',则函数返回 maxlen
	说明:1、返回 s 指向的字符串中的字符数(字符串的长度),不包括终止的空字节('\0'),但最多为 maxlen
		 2、只查看由 s 指向的字符串中的第一个 maxlen 字符,不超过 s + maxlen 位置
		 3、不是C标准,符合 POSIX.1-2008,以前版本需要 #define  _GNU_SOURCE
    

3.12、属性类型 — 函数功能测试与手动实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if WIN32
// 进行递归算法
size_t strnlen(const char *str, size_t maxlen)
{
    return ((maxlen-- > 0) && ('\0' != *str)) ? (1 + strnlen(++str, maxlen)) : 0;
}
#endif

// 常规算法
size_t my_strlen1(const char *str)
{
    const char *ptr;
    for (ptr = str; *ptr != '\0'; ++ptr)
        ;

    return ptr - str;
}
// 常规算法
size_t my_strlen2(const char *str)
{
    size_t len = 0;
    while (*str++ != '\0')
        len++;

    return len;
}

size_t my_strlen3(const char *str)
{
    return ('\0' != *str) ? (1 + strlen(++str)) : 0;
}

size_t my_strnlen(const char *str, size_t maxlen)
{
    return ((maxlen-- > 0) && ('\0' != *str)) ? (1 + my_strnlen(++str, maxlen)) : 0;
}

size_t my_strnlen1(const char *str, size_t maxlen)
{
    size_t len = 0;
    while (*str++ != '\0' && maxlen--)
        len++;

    return len;
}

int main(int argc, const char **argv)
{
    char *str = "hello world";

    printf("strlen  : %ld, %ld, %ld, %ld\n",
           strlen(str), my_strlen1(str), my_strlen1(str), my_strlen2(str));

    printf("strnlen : %ld, %ld, %ld\n",
           strnlen(str, 10), my_strnlen1(str, 10), my_strnlen(str, 10));

    printf("strnlen : %ld, %ld, %ld\n",
           strnlen(str, 20), my_strnlen1(str, 20), my_strnlen(str, 20));

    printf("\n\e[1;32msystem exited with return code %d\e[0m\n\n", 0);

    return 0;
}

  测试效果如下图所示。

3.13、转换类型 — 函数功能详细说明 :将字符串包含字符进行大小写转换/翻转

char *strupr(char *s);   
    功能:将 s 指向的字符串中小写形式转换为大写形式
	返回:指向 s 的指针(此时指向 s 的字符串已经被改变)
    说明:1、只转换 s 指向字符串中出现的小写字母,不改变其它字符
		 2、不会创建新字符串返回,而是改变原有字符串,所以不能转换字符串常量
		 3、不是标准的C库函数,在linux gcc环境下需要自行定义 
char *strlwr(char *s); 
    功能:将 s 指向的字符串中大写形式转换为小写形式
	返回:指向 s 的指针(此时指向 s 的字符串已经被改变)
    说明:1、只转换 s 指向字符串中出现的小写字母,不改变其它字符
		 2、不会创建新字符串返回,而是改变原有字符串,所以不能转换字符串常量
		 3、不是标准的C库函数,在linux gcc环境下需要自行定义
char *strrev(char *str); 
    功能:翻转 s 指向的字符串,所有字符的顺序颠倒过来(不包括'\0')。
    返回:指向翻转后的字符串指针 str
	说明:1、修改原字符串,所以不能翻转字符串常量
		 2、不是C语言标准库函数,linux gcc环境下需要自行定义
		 

3.14、转换类型 — 函数功能测试与手动实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 在windows环境下已经可以支持下面的函数功能
#if !WIN32
// 如果要使用C库函数实现
#if __CTYPE
#include <ctype.h>
// 使用C库函数实现
char *strlwr(char *str)
{
    char *tmp = str;
    while (*tmp)
    {
        *tmp = tolower(*tmp);
        tmp++;
    }
    return str;
}
char *strupr(char *str)
{
    char *tmp = str;
    while (*tmp)
    {
        *tmp = toupper(*tmp);
        tmp++;
    }
    return str;
}
#else
// 不用C库函数,自行实现
#define TOUPPER(s) ((s) >= 'a' && (s) <= 'z') ? (s - 'a' + 'A') : (s)
#define TOLOWER(s) ((s) >= 'A' && (s) <= 'Z') ? (s - 'A' + 'a') : (s)

char *strupr(char *str)
{
    char *tmp = str;
    while (*tmp)
    {
        *tmp = TOUPPER(*tmp);
        tmp++;
    }
    return str;
}

char *strlwr(char *str)
{
    char *tmp = str;
    while (*tmp)
    {
        *tmp = TOLOWER(*tmp);
        tmp++;
    }
    return str;
}

char *strrev(char *str)
{
    char *p1 = str;
    char *p2 = str + strlen(str) - 1;
    int i = strlen(str) / 2;
    while (i > 0)
    {
        *p1 ^= *p2;
        *p2 ^= *p1;
        *p1 ^= *p2;
        p1++;
        p2--;
        i--;
    }
    return str;
}
#endif // end of __CTYPE
#endif // end of WIN32

int main(int argc, const char **argv)
{
    char str[] = "Hello, I am SongShuai";
    char *ret = NULL;

    printf("Before strupr, str = %s\n", str);
    ret = strupr(str);
    printf("After  strlwr, str = %s\n", str);
    printf("               ret = %s\n", ret);
    putchar(10);

    printf("Before strlwr, str = %s\n", str);
    ret = strlwr(str);
    printf("After  strlwr, str = %s\n", str);
    printf("               ret = %s\n", ret);
    putchar(10);

    char str111[12]; // 随机内容进行测试,具体按照测试为准
    printf("Before strlwr, str = %s\n", str111);
    ret = strlwr(str111);
    printf("After  strlwr, str = %s\n", str111);
    printf("               ret = %s\n", ret);
    putchar(10);

    printf("Before strrev, str = %s\n", str);
    ret = strrev(str);
    printf("After  strlwr, str = %s\n", str);
    printf("               ret = %s\n", ret);

    printf("\n\e[1;32msystem exited with return code %d\e[0m\n\n", 0);

    return 0;
}

  测试效果如下图所示。

三、简单的总结

  综上,基本上在 string.h大大 部分函数功能都已经有了简单的说明。虽然有一些平台兼容性不好的功能函数(比如:strupr、strnlen …),但是基本上明白基本功能和特性,想要在其他平台实现兼容也是比较简单是事情。

  上面的所有的功能函数都基于 glibc-2.27 版本,想要查看源码或者其他版本的也可以了自行下载和查看:

  1、官网(虽说习惯上去官网,但下载速度真的慢): http://ftp.gnu.org/gnu/glibc/

  2、清华大学开源软件镜像站点: https://ftpmirror.gnu.org/libc/

  3、中国科技大学开源软件镜像站点: https://mirrors.ustc.edu.cn/gnu/libc/

  
  好啦,废话不多说,总结写作不易,如果你喜欢这篇文章或者对你有用,请动动你发财的小手手帮忙点个赞,当然 关注一波 那就更好了,好啦,就到这儿了,么么哒(*  ̄3)(ε ̄ *)。

上一篇:C语言 – string.h中函数功能详解与手动实现 - 02(常用函数memcpy、memmove、strcpy、strdup、strcat、strtok…)
下一篇:本文

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青椒*^_^*凤爪爪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值