说明:基于Linux系统的,多使用命令 man -f 函数名 查看函数怎么使用,切忌不要依赖别人总结好的资料。

一、函数strchr和strrchr

函数的作用:  NAME(名字)
       strchr, strrchr, strchrnul - locate character in string
                                    //翻译:在字符串中定位字符
函数的头文件:SYNOPSIS(简介)
       #include <string.h>


函数的原型:
        char *strchr(const char *s, int c)
        char *strrchr(const char *s, int c)
        参数一:指定字符串
        参数二:待查字符

函数的使用: DESCRIPTION(说明,描述)
            The  strchr() function returns a pointer to the first occurrence of the
       character c in the string s.

           The strrchr() function returns a pointer to the last occurrence of  the
       character c in the string s.

           The strchrnul() function is like strchr() except that if c is not found
       in s, then it returns a pointer to the null  byte  at  the  end  of  s,
       rather than NULL.

           Here "character" means "byte"; these functions do not work with wide or
       multibyte characters.

        /*
        翻译: strchr() 函数返回一个指向字符串 s 中字符 c 首次出现位置的指针。

              strrchr() 函数返回一个指向字符串 s 中字符 c 最后一次出现位置的指针。

              strchrnul() 函数与 strchr() 类似,不同之处在于:如果在 s 中未找到字符 c,该函数 
          将返回指向 s 末尾空字节(即终止符 '\0')的指针,而非返回 NULL。

              此处所谓的"字符"指代的是"字节";这些函数无法处理宽字符或多字节字符。
        */

函数的返回值:RETURN VALUE(返回值)
        The  strchr() and strrchr() functions return a pointer to the matched character
    or NULL if the character is not found.  The terminating null byte is considered part 
    of the string, so that if c is specified as '\0', these functions return a pointer to 
    the terminator.
        /*
            翻译:
                strchr() 和 strrchr() 函数返回一个指向匹配字符的指针,如果未找到该字符则返回
           NULL。终止空字节被视为字符串的一部分,因此如果 c 被指定为 '\0',这些函数将返回指向终
           止符的指针。
        */

  • 注意:
    • 这两个函数的功能,都是在指定的字符串s中,试图找到字符c
    • strchr()从左往右,strrchr()从右往左
    • 字符串结束标记'\0'被认为是字符串的一部分
  • 图解:

/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.30
  * @brief   strchr和strrchr自写库和官方函数应用
  *          编译:gcc 001__函数strchr和strrchr.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>

// 自己写的库
/**
 * @brief  查找字符c再字符串s的位置
 * @note   从左到右来查找这个字符的位置
 * @param  s:指定要查找的字符串
 *         c:待查字符
 * @retval 成功:返回指向找到这个字符的指针
 *         失败:返回NULL
*/
char *MyLib_StrLChr(const char *s, int c)
{
    // 1、如果传进来的字符串是空的,那就没有必要继续下面的内容了
    if (s == NULL)
        return NULL;  // 失败,返回NULL

    // 2、移动指针s获取字符串的字符,并与字符c判断是否一直,一致就退出
    while ((*s != '\0') && (*s != c))
    {
        s++;        // 指针s会一直往字符串末尾移动(直到遇到'\0'为止)
    }
     
    // 3、判断是结束符'\0',还是找到的字符c
    if (*s == '\0')
        return NULL;
    else
        return (char *)s;
}


/**
 * @brief  查找字符c再字符串s的位置
 * @note   从右到左来查找这个字符的位置
 * @param  s:指定要查找的字符串
 *         c:待查字符
 * @retval 成功:返回指向找到这个字符的指针
 *         失败:返回NULL
*/
char *MyLib_StrRChr(const char *s, int c)
{
    // 1、如果传进来的字符串是空的,那就没有必要继续下面的内容了
    if (s == NULL)
        return NULL;        // 失败,返回NULL

    const char *tmp_p = s;  // 记住最初的这个字符串的地址(也就是字符串首字符的地址)

    // 2、先将指针s移动到字符串的末尾
    while ( *s != '\0')
    {
        s++;
    }

    // 3、从右往左判断c是否存在
    while ((*s != c) && (s != tmp_p-1))
    {
        s--; 
              
    }
     
    // 4、判断是tmp_p,还是找到的字符c
    if (s == tmp_p-1)
        return NULL;
    else
        return (char *)s;
}


// 主函数
int main(int argc, char const *argv[])
{
    
    // (1)、官方写的库
    // 1、strchr函数(从左往右查找字符串s1找到要的字符c1)
    const char *s1 = "shijienameda";
    int   c1       = 'i';
    char *p1       = strchr(s1, c1);
    printf("p1 == %s\n", p1);

    // 2、strrchr函数(从右往左查找字符串s2找到要的字符c2)
    const char *s2 = "shijienameda";
    int   c2       = 'i';
    char *p2       = strrchr(s2, c2);
    printf("p2 == %s\n", p2);


    // (2)、自己写的库
    // 1、MyLib_StrLChr函数
    const char *s3 = "shijienameda";
    int   c3       = 'a';
    char *p3       = MyLib_StrLChr(s3, c3);
    printf("p3 == %s\n", p3);

    // 2、MyLib_StrRChr函数
    const char *s4 = "shijienameda";
    int   c4       = 'a';
    char *p4       = MyLib_StrRChr(s4, c4);
    printf("p4 == %s\n", p4);

    return 0;
}

二、函数strstr

函数的作用:  NAME(名字)  
                strstr, strcasestr - locate a substring
                    //翻译:定位子字符串

函数的头文件:SYNOPSIS(简介)
        #include <string.h>

函数的原型:
    char *strstr(const char *haystack, const char *needle);
    参数一:指定的字符串
    参数二:需要查找的字串


函数的使用:DESCRIPTION(说明,描述)
       The strstr() function finds the first occurrence of the substring needle in the 
  string haystack.  The terminating null bytes ('\0') are not compared.
       The strcasestr() function is like strstr(), but ignores the case of both 
  arguments.


    /*
        翻译:
             strstr() 函数用于在字符串 haystack 中查找子字符串 needle 的首次出现位置。终止空字节 ('\0') 不会参与比较。

            strcasestr() 函数与 strstr() 类似,但会忽略两个参数的大小写差异。
    */

 函数的返回值:RETURN VALUE(返回值)
        These functions return a pointer to the beginning of the located substring,
    or NULL if the substring is not found.

        /*
            翻译:
                这些函数返回一个指向找到的子字符串起始位置的指针,如果未找到子字符串则返回 
        */

  • 图解:

  • 示例代码
/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.30
  * @brief   strstr自写库和官方函数应用
  *          编译:gcc 002__函数strstr.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>

// 自己写的库
/**
 * @brief  在指定的一个字符串中,找到一个子串
 * @note   None
 * @param  haystack:指定要查找的字符串
 *         needle:  待查子串
 * @retval 成功:返回指向找到这个子串的指针
 *         失败:返回NULL
*/
char *MyLib_StrStr(const char *haystack, const char *needle)
{
   // 1、如果传进来的字符串是空的,那就没有必要继续下面的内容了
    if ( (haystack == NULL) || (needle == NULL))
        return NULL; 

    // 初始化
    const char *tmp_p1 = haystack;
    const char *tmp_p2 = needle;

    const char *p1     = haystack;
    const char *p2     = needle;

    // 2、遍历haystack字符串,找到所有可能
    while ( *tmp_p1 != '\0')
    {
        // 在进去比较循环之前,将p1和p2的最初的为止(循环之前)进行保留
        p1 = tmp_p1;
        p2 = tmp_p2;

        // 进入循环一次比较两个字符串的字符是否一致,防止比较的字符串在末尾
        while ((*p1 == *p2) && (*p1 != '\0') && (*p2 != '\0'))
        {
            p1++;
            p2++;

        }

        if (*p2 == '\0')            // 判断p2是否指向'\0',是的话,就意味着找到了haystack中的子串needle
        {
            return (char *)tmp_p1;  // 返回haystack中的子串的为止
        }
        
        tmp_p1++;
    }

    // 3、没有找到子串,就返回NULL
    return NULL;

}

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、官方写的库
    const char *s1 = "chuangqianmingyueguang,yishidishangshuang";
    const char *s2 = "yishi";
    char *p1 = strstr(s1, s2);
    printf("p1 == %s\n", p1);


    // (2)、自己写的库
    const char *s3 = "chuangqianmingyueguang,yishidishangshuang";
    const char *s4 = "yishi";
    char *p2 = MyLib_StrStr(s3, s4);
    printf("p2 == %s\n", p2);

    return 0;
}

三、函数strlen

函数的作用:  NAME(名字)
       strlen - calculate the length of a string
        //翻译:strlen - 计算字符串长度

函数的头文件:SYNOPSIS(简介)
       #include <string.h>

函数的原型:
       size_t strlen(const char *s);
       参数一:需要求长度的字符串

函数的使用: DESCRIPTION(说明,描述)
         The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('\0').
         /*
            翻译:
                strlen() 函数计算字符串 s 的长度(不包含终止空字节 '\0')。
         */

 函数的返回值:RETURN VALUE(返回值):
          The strlen() function returns the number of bytes in the string pointed to by s.
        /*
            翻译:
                strlen() 函数返回字符串 s 的字节长度。
         */

  • 图解

  • 示例代码:
/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.30
  * @brief   strlen自写库和官方函数应用
  *          编译:gcc 002__函数strlen.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>

// 给类型取个别名
typedef unsigned long mylib_size_t;

// 自己写的库
/**
 * @brief  求一个指定字符串的长度
 * @note   None
 * @param  s:需要求长度的字符串
 * @retval 成功:返回字符串的长度,不包含字符串结束标志'\0'
 *         失败:返回1
*/
mylib_size_t MyLib_StrLen(const char *s)
{
    // 1、如果传进来的字符串是空的,那就没有必要继续下面的内容了
    if (s == NULL)
        return 1;  
    
    // 2、计算从左到右,一直到'\0',有多少个字符
    mylib_size_t cnt = 0;
    while (*s != '\0')
    {
        cnt++;
        s++;
    }

    // 3、返回计算的字符串的长度
    return cnt;
    

}

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、官方写的库
    const char buf1[256] = "moranhuishou,narenquezaidenghuolanshanchu";
    size_t len1 = strlen(buf1);
    printf("len1 == %lu\n", len1);

    // (2)、自己写的库
    const char buf2[256] = "moranhuishou,narenquezaidenghuolanshanchu";
    size_t len2 = MyLib_StrLen(buf2);
    printf("len2 == %lu\n", len2);

    return 0;
}

四、函数strcpy和strncpy

函数的作用:  NAME(名字)
       strcpy, strncpy - copy a string
       // 翻译:strcpy, strncpy - 复制字符串

函数的头文件:SYNOPSIS(简介)
       #include <string.h>

函数的原型:
       char *strcpy(char *dest, const char *src);
       char *strncpy(char *dest, const char *src, size_t n);

       参数一(dest):指向目标内存,存储复制的字符串
       参数二(src):指向待复制的字符串
       参数三(n):规定最多将src中的n个字节复制到dest内存里面

函数的使用: DESCRIPTION(说明,描述)
           The  strcpy()  function  copies  the string pointed to by src, including the
      terminating null byte ('\0'), to the buffer pointed to by dest.  The strings may
      not overlap, and the destination
           string dest must be large enough to receive the copy.  Beware of buffer 
      overruns!(See BUGS.)

           The strncpy() function is similar, except that at most n bytes of src are
      copied.  Warning: If there is no null byte among the first n bytes of src, the
      string placed in  dest  will  not  be    null-terminated.

           If the length of src is less than n, strncpy() writes additional null bytes to
      dest to ensure that a total of n bytes are written.

       A simple implementation of strncpy() might be:
          //翻译:strncpy() 的一个简单实现可能如下:
           char * strncpy(char *dest, const char *src, size_t n)
           {
               size_t i;

               for (i = 0; i < n && src[i] != '\0'; i++)
                   dest[i] = src[i];
               for ( ; i < n; i++)
                   dest[i] = '\0';

               return dest;
           }
      /*
        翻译:
           strcpy() 函数将 src 所指向的字符串(包括终止空字节 '\0')复制到 dest 所指向的 
        缓冲区中。两个字符串不得重叠,且目标字符串 dest 必须具有足够的空间来接收复制内容。请
        注意缓冲区溢出!(参见 BUGS 章节)

           strncpy() 函数功能类似,但最多只复制 src 的前 n 个字节。
           警告:如果 src 的前 n 个字节中没有空字节,则放置在 dest 中的字符串将不会以空字符结尾。

           如果 src 的长度小于 n,strncpy() 会向 dest 写入额外的空字节,确保总共写入 n 个字节。

      */

 函数的返回值:RETURN VALUE(返回值)
        The strcpy() and strncpy() functions return a pointer to the destination string
    dest.
        /*
            翻译:
                strcpy() 和 strncpy() 函数返回指向目标字符串 dest 的指针。
        */

  • 注意:
    • 复制src字符串的时候,也会将'\0',一并复制到dest中
    • 这两个函数的功能,都是将src中的字符串,复制到dest中
    • strcpy()没有边界控制,因此可能会由于src的过长而导致内存溢出
    • strncpy()有边界控制,最多复制n+1个字节(其中最后一个是'\0')到dest中
  • 图解

  • 示例代码:
/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.30
  * @brief   strcpy自写库和官方函数应用
  *          在ubuntu编译:gcc 004__函数strcpy.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>

// 自己写的库
/**
 * @brief  复制字符串
 * @note   None
 * @param  dest:指向目标的内存,存储复制的字符串
 *         src: 指向待复制的字符串
 * @retval 成功:返回一个指针,这个指针指向复制后的字符串,等价于dest
 *         失败:返回NULL
*/
char* MyLib_StrCpy(char *dest, const char *src)
{
    // 1、如果传进来的指针是有误的(比如:NULL),没有必要继续下面的内容了
    if ( (dest == NULL) || (src == NULL))
    {
        return NULL;
    }
    
    char *tmp_p = dest;     // 记录dest指针最初指向的地址

    // 2、根据str字符串的结束符'\0',来进行一维赋值给dest内存
    while (*src != '\0')
    {
        *tmp_p = *src;      // 赋值操作,将src内存里面的内容复制到dest内存中
        tmp_p++;
        src++;
    }
    *tmp_p = '\0';          // 末尾赋值一个结束符,防止后面复制后的字符串打印有问题   

    // 3、返回指向dest内存的地址
    return dest;
}


/**
 * @brief  复制字符串
 * @note   None
 * @param  dest:指向目标的内存,存储复制的字符串
 *         src: 指向待复制的字符串
 *         n:   规定最多将src中的n个字节复制到dest内存中
 * @retval 成功:返回一个指针,这个指针指向复制后的字符串,等价于dest
 *         失败:返回NULL
*/
char* MyLib_StrNCpy(char *dest, const char *src, unsigned long n)
{
    // 1、如果传进来的指针是有误的(比如:NULL)或者需要复制的数是0,没有必要继续下面的内容了
    if ( (dest == NULL) || (src == NULL) || (n == 0))
    {
        return NULL;
    }
    
    char *tmp_p = dest;     // 记录dest指针最初指向的地址

    // 2、根据n来限定复制stc字符串内容给dest内存的范围
    int len = strlen(src);
    if (n>len)
    {
        n=len;
    }
    
    while (n--)
    {
        *tmp_p = *src;      // 赋值操作,将src内存里面的内容复制到dest内存中
        tmp_p++;
        src++;
    }
    *tmp_p = '\0';          // 末尾赋值一个结束符,防止后面复制后的字符串打印有问题   

    // 3、返回指向dest内存的地址
    return dest;
}



// 主函数
int main(int argc, char const *argv[])
{
    // (1)、官方写的库
    // 1、strcpy函数
    char  dest_buf1[256]     = {0};                 // 目标内存1
    const char src_buf1[128] = "shijienameda";      // 要复制的字符串1
    char *p1 = strcpy(dest_buf1, src_buf1);         // 有点危险,没有边界
    printf("p1        == %s\n", p1);
    printf("dest_buf1 == %s\n", dest_buf1);

    // 2、strncpy函数
    char  dest_buf2[256]     = {0};                 // 目标内存2
    const char src_buf2[1024] = "shijienameda";     // 要复制的字符串2
    char *p2 = strncpy(dest_buf2, src_buf2, 6);     // 比较安全,可以控制复制的范围,且最大为n+1(包括字符串末尾的'\0')
    printf("p2        == %s\n", p2);
    printf("dest_buf2 == %s\n", dest_buf2);
    
    // (2)、自己写的库
    // 1、MyLib_StrCpy函数
    char  dest_buf3[256]     = {0};                 // 目标内存3
    const char src_buf3[128] = "shijienameda";      // 要复制的字符串3
    char *p3 = MyLib_StrCpy(dest_buf3, src_buf3);   // 有点危险,没有边界
    printf("p3        == %s\n", p3);
    printf("dest_buf3 == %s\n", dest_buf3);

    // 2、MyLib_StrNCpy函数
    char  dest_buf4[256]     = {0};                 // 目标内存4
    const char src_buf4[128] = "shijienameda";      // 要复制的字符串4
    char *p4 = MyLib_StrNCpy(dest_buf4, src_buf4, 6);   // 比较安全,可以控制复制的范围,且最大为n+1(包括字符串末尾的'\0')
    printf("p4        == %s\n", p4);
    printf("dest_buf4 == %s\n", dest_buf4);

    return 0;
}

五、函数strcmp和strncmp 

函数的作用:  NAME(名字)
       strcmp, strncmp - compare two strings
                        //翻译:比较两个字符串

函数的头文件:SYNOPSIS(简介)
       #include <string.h>

函数的原型:
       int strcmp(const char *s1, const char *s2);
       int strncmp(const char *s1, const char *s2, size_t n);

       参数一(s1):待比较的字符串
       参数二(s2):待比较的字符串
       参数三(n): 比较字符串的前n个字节

函数的使用: DESCRIPTION(说明,描述)
              The  strcmp()  function compares the two strings s1 and
         s2.  The locale is not taken into account  (for  a  lo‐
         cale-aware comparison, see strcoll(3)).  The comparison
         is done using unsigned characters.

              strcmp() returns an integer indicating  the  result  of
         the comparison, as follows:

         • 0, if the s1 and s2 are equal;

         • a negative value if s1 is less than s2;

         • a positive value if s1 is greater than s2.

              The  strncmp()  function is similar, except it compares
         only the first (at most) n bytes of s1 and s2.
  
        /*
            翻译:
                strcmp() 函数用于比较两个字符串 s1 和 s2。该函数不会考虑区域设置(如需进行区域 
           设置感知的比较,请参阅 strcoll(3))。比较使用无符号字符进行。

                strcmp() 返回一个整数来表示比较结果,具体如下:
                如果 s1 和 s2 相等,则返回 0;
                如果 s1 小于 s2,则返回一个负值;
                如果 s1 大于 s2,则返回一个正值。
                strncmp() 函数功能类似,不同之处在于它仅比较 s1 和 s2 的前 n 个字节(最多)
        
        */
函数的返回值:RETURN VALUE(返回值)
                 The strcmp() and strncmp() functions return an  integer
             less than, equal to, or greater than zero if s1 (or the
             first n bytes thereof) is found,  respectively,  to  be
             less than, to match, or be greater than s2.
            /*
             翻译:
                 strcmp() 和 strncmp() 函数返回一个整数,该整数根据比较结果可能小于零、等于零
             或大于零。具体来说:
                 如果发现 s1(或其前 n 个字节)小于 s2,则返回一个小于零的整数;
                 如果发现 s1(或其前 n 个字节)等于 s2,则返回零;
                 如果发现 s1(或其前 n 个字节)大于 s2,则返回一个大于零的整数。

            */

  • 注意:
    • 比较两个字符串是否相等,实际上比较的是两个字符串的字符的ASCII码值的大小
    • 从左到右逐个比较两个字符串每一个字符,当能"决出胜负"的时候立刻停止比较
  • 图解:

/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.31
  * @brief   strcmp和strncmp自写库和官方函数应用
  *          在ubuntu编译:gcc 005__函数strcmp和strncmp.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>


// 给类型取个别名
typedef unsigned long mylib_size_t;


// 自己写的库
/**
 * @brief  比较两个字符串是否一致
 * @note   None
 * @param  s1:待比较的字符串1
 *         s2:待比较的字符串2
 * @retval 成功:当s1大于、等于或者小于s2时,返回1、0或者-1
 *         失败:返回2
*/
int MyLib_StrCmp(const char *s1, const char *s2)
{
    // 1、如果传进来的指针是有误的(比如:NULL),没有必要继续下面的内容了
    if ((s1 == NULL) || (s2 == NULL))
    {
       return 2;
    }
    
    // 2、依次比较字符串的字符(保证即使两个字符串长度不一样,当前面一致,也能够知道其不同的地方)
    while ( (*s1 != '\0' ) && (*s2 != '\0') && (*s1 == *s2))
    {
        s1++;
        s2++;
    }
    
    // 3、ascii码值对比、长短不一的情况再次判断
    if (*s1 > *s2)
        return 1;   // s1字符的ascii码值 > s2字符的ascii码值
    else if(*s1 < *s2)
        return -1;  // s1字符的ascii码值 < s2字符的ascii码值
    else
        return 0;   // s1字符的ascii码值 == s2字符的ascii码值
    
}

/**
 * @brief  比较两个字符串是否一致
 * @note   None
 * @param  s1:待比较的字符串1
 *         s2:待比较的字符串2
 *         n: 比较两个字符串的前n个字节
 * @retval 成功:当s1大于、等于或者小于s2时,返回1、0或者-1
 *         失败:返回2
*/
int MyLib_StrNCmp(const char *s1, const char *s2, mylib_size_t n)
{
    // 1、如果传进来的指针是有误的(比如:NULL)、或者为0的情况,没有必要继续下面的内容了
    if ((s1 == NULL) || (s2 == NULL) || (n == 0))
    {
       return 2;
    }
    
    // 2、依次比较字符串的字符(保证即使两个字符串长度不一样,当前面一致,也能够知道其不同的地方)
    while ( (n!=1) && (*s1 == *s2) && (*s1 != '\0' ) && (*s2 != '\0'))
    {
        s1++;
        s2++;
        n--;
    }
    
    // 3、ascii码值对比、长短不一的情况再次判断
    if (*s1 > *s2)
        return 1;   // s1字符的ascii码值 > s2字符的ascii码值
    else if(*s1 < *s2)
        return -1;  // s1字符的ascii码值 < s2字符的ascii码值
    else
        return 0;   // s1字符的ascii码值 == s2字符的ascii码值
    
}



// 主函数
int main(int argc, char const *argv[])
{
    
    // (1)、官方写的库
    // 1、strcmp函数
    const char password1[128]  = "mq3220";
    const char intput_pw1[128] = "mq3220";
    if (strcmp(password1, intput_pw1) == 0)     // 两个字符串的字符都相等,返回0,否则返回非0
        printf("(strcmp)输入密码正确!\n");
    else
        printf("(strcmp)输入密码错误!\n");        
    
    // 2、strncmp函数
    const char password2[128]   = "mq3220";
    const char intput_pw2[128]  = "mq3220";
    if (strncmp(password2, intput_pw2, 3) == 0)   // 两个字符串的前n个字符都相等,返回0,否则返回非0
        printf("(strncmp)输入密码正确!\n");
    else
        printf("(strncmp)输入密码错误!\n");       

    // (2)、自己写的库
    // 1、MyLib_StrCmp函数
    const char password3[128]  = "mq3220";
    const char intput_pw3[128] = "mq3220";
    if (MyLib_StrCmp(password3, intput_pw3) == 0)     // 两个字符串的字符都相等,返回0,否则返回非0
        printf("(MyLib_StrCmp)输入密码正确!\n");
    else
        printf("(MyLib_StrCmp)输入密码错误!\n");  

    // 2、MyLib_StrNCmp函数
    const char password4[128]   = "mq3220";
    const char intput_pw4[128]  = "mq32207";
    if (MyLib_StrNCmp(password4, intput_pw4, 100) == 0)   // 两个字符串的前n个字符都相等,返回0,否则返回非0
        printf("(MyLib_StrNCmp)输入密码正确!\n");
    else
        printf("(MyLib_StrNCmp)输入密码错误!\n");     


    return 0;
}

六、函数strcat与strncat

函数的作用:  NAME(名字)
       strcat, strncat - concatenate two strings
                        //翻译:拼接两个字符串

函数的头文件:SYNOPSIS(简介)
       #include <string.h>

函数的原型:
       char *strcat(char *dest, const char *src);
       char *strncat(char *dest, const char *src, size_t n);

       参数一(dest):指向目标内存,最终存储拼接之后的字符串
       参数二(src): 指向需要拼接的字符串,最终将src拼接到dest后面
       参数二(n):   规定最多将src中的n个字节拼接到dest后面

函数的使用: DESCRIPTION(说明,描述)
               The  strcat() function appends the src string to the dest string, over‐
           writing the terminating null byte ('\0') at the end of dest,  and  then
           adds  a  terminating  null  byte.  The strings may not overlap, and the
           dest string must have enough space for the  result.   If  dest  is  not
           large  enough, program behavior is unpredictable; buffer overruns are a
           favorite avenue for attacking secure programs.
           /*    
                翻译:
                    strcat() 函数将 src 字符串追加到 dest 字符串的末尾,覆盖 dest 末尾的终止
                空字节 ('\0'),然后添加一个新的终止空字节。字符串之间不能重叠,且 dest 字符串必
                须具有足够空间来容纳结果。如果 dest 空间不足,程序行为将不可预测;缓冲区溢出是攻
                击安全程序的一种常用手段。

           */
            
           The strncat() function is similar, except that
               *  it will use at most n bytes from src; and
               *  src does not need to be null-terminated if it  contains  n  or  more
           bytes.
               As  with  strcat(),  the resulting string in dest is always null-termi‐
           nated.
            /*
                翻译:
                    strncat() 函数功能类似,但有以下区别:
                        它最多只会使用 src 中的 n 个字节;
                        如果 src 包含 n 个或更多字节,则它不需要以空字符 ('\0') 结尾。
                    与 strcat() 一样,目标字符串 dest 的结果总是以空字符 ('\0') 结尾的。
            */
            

               If src contains n or more bytes, strncat() writes n+1 bytes to dest  (n
           from  src plus the terminating null byte).  Therefore, the size of dest
           must be at least strlen(dest)+n+1.
           /*
           翻译:
               strncat() 函数的行为可以总结如下:

                    写入字节数: 如果 src 的前 n 个字节中没有遇到终止空字节 (\0),则
               strncat() 会向 dest 写入 n + 1 个字节。
                    n 个字节 来自 src。
                    1 个字节 是函数自动添加的终止空字节 (\0)。
                    目标缓冲区大小: 因此,为了安全操作,目标数组 dest 的大小必须至少为
               strlen(dest) + n + 1。
                    strlen(dest): dest 原始字符串的长度(不包括原有的终止空字节)。
                    n: 最多要追加的字符数。
                    + 1: 为函数自动添加的终止空字节预留空间。
                    
           */
    
            A simple implementation of strncat() might be:
                //翻译:以下是 strncat() 函数的一个简单实现示例:
           char *strncat(char *dest, const char *src, size_t n)
           {
               size_t dest_len = strlen(dest);
               size_t i;

               for (i = 0 ; i < n && src[i] != '\0' ; i++)
                   dest[dest_len + i] = src[i];
               dest[dest_len + i] = '\0';

               return dest;
           }

 函数的返回值:RETURN VALUE(返回值)
           The strcat() and strncat() functions return a pointer to the  resulting
       string dest.
        /*
        翻译:
            strcat() 和 strncat() 函数返回一个指向结果字符串 dest 的指针。
        */

  • 注意:
    • 这两个函数的功能,都是将src中的字符串,复制拼接到dest的末尾
    • strcat()没有边界控制,因此可能会由于src的过长而导致内存溢出(越界)、
    • strncat()有边界控制,最多复制n+1个字符(其中最后一个是'\0')到dest的末尾
  • 图解:
  • 示例代码
    /**
      ******************************************************************************
      * @file    test.c
      * @author  MChine慕青
      * @version V0.0.1
      * @date    2025.08.31
      * @brief   strcat和strncat自写库和官方函数应用
      *          在ubuntu编译:gcc 006__函数strcat和strncat.c
      *          执行:./a.out
      * 
      ******************************************************************************
      * @attention
      *
      *  本文档只供学习使用,不得商用,违者必究
      * 
      *  有疑问或者建议:3211735057@qq.com
      * 
      ******************************************************************************
      */
    #include <stdio.h>
    #include <string.h>
    
    // 给类型取个别名
    typedef unsigned long mylib_size_t;
    
    
    // 自己写的库
    /**
     * @brief  将两个字符串拼接起来
     * @note   None
     * @param  dest:指向目标内存,最终存储拼接之后的字符串
     *         src: 指向需要拼接的字符串,最终将src拼接到dest的后面
     * @retval 成功:返回一个指针,指向拼接后的字符串,等价于dest
     *         失败:返回NULL
    */
    char* MyLib_StrCat(char *dest, const char *src)
    {
    
        // 1、如果传进来的指针是有误的(比如:NULL),没有必要继续下面的内容了
        if ( (dest == NULL)  || (src == NULL))
        {
            return NULL;
        }
    
        char *p1       = dest;
        const char *p2 = src; 
    
        // 2、将指针p1移动到字符串的末尾(这个'\0'符号的位置)
        while (*p1 != '\0')
        {
            p1++;
        }
    
        // 3、将src字符串的字符,复制到dest中
        while (*p2 != '\0')
        {
            *p1 = *p2;
            p1++;
            p2++;
        }
    
        // 4、补回一个'\0'字符给dest字符串
        *p1 = '\0';
    
        // 5、返回dest最初指向的内存位置
        return dest;
    
    }
    
    /**
     * @brief  将两个字符串拼接起来
     * @note   None
     * @param  dest:指向目标内存,最终存储拼接之后的字符串
     *         src: 指向需要拼接的字符串,最终将src拼接到dest的后面
     *         n:   规定最多将src中的前n个字符拼接到dest的后面
     * @retval 成功:返回一个指针,指向拼接后的字符串,等价于dest
     *         失败:返回NULL
    */
    char* MyLib_StrNCat(char *dest, const char *src, mylib_size_t n)
    {
     
        // 1、如果传进来的指针是有误的(比如:NULL)、或者为0的情况,没有必要继续下面的内容了
        if ( (dest == NULL)  || (src == NULL) || (n == 0))
        {
            return NULL;
        }
    
        char *p1       = dest;
        const char *p2 = src; 
    
        // 2、将指针p1移动到字符串的末尾(这个'\0'符号的位置)
        while (*p1 != '\0')
        {
            p1++;
        }
    
        // 3、将src字符串的字符,复制到dest中
        while ((*p2 != '\0') && (n--))
        {
            *p1 = *p2;
            p1++;
            p2++;
        }
    
        // 4、补回一个'\0'字符给dest字符串
        *p1 = '\0';
    
        // 5、返回dest最初指向的内存位置
        return dest;
    
    }
    
    
    // 主函数
    int main(int argc, char const *argv[])
    {
        
        // (1)、官方写的库
        // 1、strcat函数
        char dest_buf[256] = "qingge";               // 目标字符串
        const char src_buf1[128] = ",nihaoshuai";    // 要拼接的字符串1
        const char src_buf2[128] = ",zhendejiade";   // 要拼接的字符串2   
    
        char *p1 = strcat(dest_buf, src_buf1);
        printf("p1 == %s\n", p1);
        printf("dest_buf == %s\n", dest_buf);
    
        // 2、strncat函数
        char *p2 = strncat(dest_buf, src_buf2, 7);
        printf("p2 == %s\n", p2);
        printf("dest_buf == %s\n", dest_buf);
    
    
        // (2)、自己写的库
        // 1、MyLib_StrCat函数
        char dest_buf1[256] = "qingge";               // 目标字符串
        const char src_buf3[128] = ",nihaoshuai";    // 要拼接的字符串1
        const char src_buf4[128] = ",zhendejiade";   // 要拼接的字符串2   
    
        char *p3 = MyLib_StrCat(dest_buf1, src_buf3);
        printf("p3 == %s\n", p3);
        printf("dest_buf1 == %s\n", dest_buf1);
    
        // 2、MyLib_StrNCat函数
        char *p4 = MyLib_StrNCat(dest_buf1, src_buf4, 7);
        printf("p4 == %s\n", p4);
        printf("dest_buf1 == %s\n", dest_buf1);
    
        return 0;
    }
    

七、函数strtok

函数的作用:  NAME(名字)
       strtok, strtok_r - extract tokens from strings        
                         //翻译:将某个字符串,按照指定的分隔符拆解为字串

函数的头文件:SYNOPSIS(简介)
       #include <string.h>

函数的原型:
      char *strtok(char *str, const char *delim);    
      参数一:指定要拆解的字符串
      参数二:分隔符,此处可以指定多个分隔符,形成一个分隔符串

函数的使用: DESCRIPTION(说明,描述)
           The  strtok()  function breaks a string into a sequence of zero or 
       morenonempty tokens.  On the first call  to  strtok(),  the  string  
       to  beparsed should be specified in str.  In each subsequent call that 
       should parse the same string, str must be NULL.
       /*
        翻译:
            strtok() 函数将一个字符串分割成一系列零个或多个非空令牌。在第一次调用 strtok() 时,
        要解析的字符串应在 str 中指定。在后续解析同一字符串的每次调用中,str 必须为 NULL。
       */

           The delim argument specifies a set of bytes that delimit the tokens  
       in the  parsed  string.  The caller may specify different strings in 
       delim in successive calls that parse the same string.
       /*
        翻译:
            delim 参数指定了用于分隔已解析字符串中令牌的一组字节。调用者可以在解析同一字符串的连
        续调用中指定不同的 delim 字符串。
       */

           Each call to strtok() returns a pointer  to  a  null-terminated  
       string containing the next token.  This string does not include the 
       delimiting byte.  If no more tokens are found, strtok() returns NULL.
       /*
        翻译:
            每次调用 strtok() 都会返回一个指向以空字符结尾的字符串的指针,该字符串包含下一个令
        牌。此字符串不包含分隔字节。如果找不到更多令牌,strtok() 返回 NULL。
       */

           A sequence of calls to strtok() that operate on the same  string  
       main‐tains a pointer that determines the point from which to start 
       searching for the next token.  The first call to strtok() sets  this  
       pointer  to point  to the first byte of the string.  The start of the 
       next token is determined by scanning forward for the next nondelimiter 
       byte  in  str.If  such  a  byte is found, it is taken as the start of 
       the next token.If no such byte is found, then there are no more tokens,  
       and  strtok() returns NULL.  (A string that is empty or that contains 
       only delimiters will thus cause strtok() to return NULL on the first 
       call.)
       /*
        翻译:
            对同一字符串进行一系列 strtok() 调用会维护一个指针,该指针决定了从哪个位置开始搜索下
        一个令牌。第一次调用 strtok() 时,将此指针设置为指向字符串的第一个字节。下一个令牌的起始
        位置通过向前扫描查找下一个非分隔符字节来确定。如果找到这样的字节,则将其作为下一个令牌的
        起始位置。如果找不到这样的字节,则表示没有更多令牌,strtok() 返回 NULL。(因此,空字符串
        或仅包含分隔符的字符串将在第一次调用时就使 strtok() 返回 NULL。)
       */

           The end of each token is found by scanning  forward  until  either  
       the next  delimiter byte is found or until the terminating null byte ('\0')
       is encountered.  If a delimiter byte is found, it is overwritten with a
       null  byte to terminate the current token, and strtok() saves a pointer
       to the following byte; that pointer will be used as the starting  point
       when  searching  for  the next token.  In this case, strtok() returns a
       pointer to the start of the found token.
       /*
        翻译:
            每个令牌的结束位置通过向前扫描直到找到下一个分隔符字节或遇到终止空字节('\0')来确
        定。如果找到分隔符字节,它会被覆盖为一个空字节以终止当前令牌,并且 strtok() 会保存一个指
        向后续字节的指针;该指针将在搜索下一个令牌时用作起始点。在这种情况下,strtok() 返回一个
        指向找到的令牌起始位置的指针。
       */

           From the above description, it follows that a sequence of two  or  
       morecontiguous  delimiter  bytes in the parsed string is considered to be 
       a single delimiter, and that delimiter bytes at the start or end  of  the
       string  are  ignored.  Put another way: the tokens returned by strtok()
       are always nonempty strings.   Thus,  for  example,  given  the  string
       "aaa;;bbb,",  successive  calls  to strtok() that specify the delimiter
       string ";," would return the strings "aaa" and "bbb", and then  a  null
       pointer.
       /*
        翻译:
            根据以上描述,解析字符串中两个或多个连续的分隔符字节被视为单个分隔符,并且字符串开头
        或结尾的分隔符字节会被忽略。换句话说:strtok() 返回的令牌始终是非空字符串。因此,例如,
        给定字符串 "aaa;;bbb,",连续调用指定分隔符字符串 ";," 的 strtok() 将返回字符串 "aaa" 
        和 "bbb",然后返回空指针。
       */


 函数的返回值:RETURN VALUE(返回值)
               The strtok() and strtok_r() functions return a pointer to the next  
         to‐ken, or NULL if there are no more tokens.
       /*
        翻译:
            strtok() 函数返回一个指向下一个令牌的指针,如果没有更多令牌,则返回 NULL。
       */

  • 注意:
    • 该函数会将改变原始字符串str,使其所包含的所有分隔符变成结束标记'\0'
    • 由于该函数需要更改字符串str,因此str指向内存必须是可写的
    • 首次调用时str指向原始字符串,此后每次调用str用NULL代替
  • 图解

  • 示例代码:
/**
  ******************************************************************************
  * @file    test.c
  * @author  MChine慕青
  * @version V0.0.1
  * @date    2025.08.30
  * @brief   strtok自写库和官方函数应用
  *          在ubuntu编译:gcc 007__函数strtok.c
  *          执行:./a.out
  * 
  ******************************************************************************
  * @attention
  *
  *  本文档只供学习使用,不得商用,违者必究
  * 
  *  有疑问或者建议:3211735057@qq.com
  * 
  ******************************************************************************
  */
#include <stdio.h>
#include <string.h>

// 自己写的库
/**
 * @brief  将某个字符串,按照指定的分隔符拆解为子串
 * @note   None
 * @param  str:  指定要拆解的字符串(该内存空间必须可写)
 *         delim:分隔符,此处可以指定多个分隔符,形成一个分隔字符串
 * @retval 成功:返回指向子串的指针
 *         失败:返回NULL,代表拆解完毕
*/
char* MyLib_StrTok(char *str, const char *delim)
{
    static char* token_next_p = NULL;   // 保存上一次的分割的位置
    char *token_start_p = NULL;         // 当前token的起始位置

    // 1、如果传进来的新字符串,则重置token_next_p
    if (str != NULL)
    {
        token_next_p = str;
    }

    // 2、如果token_next_p为NULL或已到字符串末尾,则返回NULL
    if ( ( token_next_p == NULL) || (*token_next_p == '\0'))
    {
        return NULL;
    }

    // 3、跳出前面的分隔符
    while ( *token_next_p != '\0')
    {
        const char *d = delim;
        int delim_flag = 0;

        while (*d != '\0')
        {
            if (*token_next_p == *d)
            {
                delim_flag = 1;
                break;
            }
            d++;
        }

        if (!delim_flag)
        {
            break;
        }
        
        token_next_p++;
    }
    
    // 4、如果已经到字符串末尾,返回NULL
    if (*token_next_p == '\0')
    {
        token_next_p = NULL;
        return NULL;
    }
    
    // 5、记录token起始位置
    token_start_p = token_next_p;

    // 6、查找token结束位置(下一个分隔符)
    while (*token_next_p !='\0')
    {
        const char *d = delim;
        int delim_flag = 0;

        while (*d != '\0')
        {
            if (*token_next_p == *d)
            {
                delim_flag = 1;
                break;
            }
            d++;
        }

        if (delim_flag)
        {
            *token_next_p = '\0';       // 用'\0'字符替换分隔符
            token_next_p++;             // 指向下一个字符作为下次起点
            return token_start_p;       // 返回档当前token
        }
        
        token_next_p++;
    }
    
    // 7、token之后没有更多的分隔符(最后一个token)
    token_next_p = NULL;
    return token_start_p;
}

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、官方写的库
    char str[] = "wo ben lai yao xingzou jianghu de! dan shi yu jian ni, wojueding ting yixia";

    char *token_p = strtok(str, " !,");
    while ( token_p!=NULL )
    {
        printf("token_p == %s\n", token_p);
        token_p = strtok(NULL, " !,");
    }


    // (2)、自己写的库
    char str1[] = "zhong li xunta qianbaidu! moranhuishou, naren quezai, denghuolanshanchu";
    char *token_p1 = MyLib_StrTok(str1, " !,");
    while ( token_p1!=NULL )
    {
        printf("token_p1 == %s\n", token_p1);
        token_p1 = MyLib_StrTok(NULL, " !,");
    }
    return 0;
}

        本节内容到这里就结束咯,有问题的朋友可以评论区留言.......

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐