• c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))


    上篇文章介绍了一些常用的字符串函数,大家可以跳转过去浏览一下:c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(上))_总之就是非常唔姆的博客-CSDN博客

    今天接着来介绍一些: 


    目录

    一.字符串查找

    1.strstr()

    1.1示例

    1.2注意事项:

    1.3模拟实现

     2.strtok()

     2.1示例

    2.2注意事项

     二.错误信息报告

    1.strerror()

     1.1示例

    1.2注意事项:

     三.内存操作函数

    1.memcpy()

    1.1示例

    1.2注意事项

    2.memmove()

     2.1示例

     2.2注意事项:

    3.memset()

     3.1示例

     3.2注意事项:

     4.memcmp()

    4.1示例

    4.2注意事项:


    一.字符串查找

    1.strstr()

    strstr是一个C标准库函数,用于在一个字符串中查找另一个字符串的第一次出现的位置。它的原型如下:

    char *strstr(const char *haystack, const char *needle);

    strstr函数接受两个参数,haystack是要搜索的字符串,needle是要查找的子字符串。函数返回一个指向第一次出现的子字符串的指针,如果找不到子字符串,则返回NULL

    下面是strstr函数的工作原理:

    1. 首先,strstr函数会在haystack字符串中搜索needle字符串的第一个字符

    2. 一旦找到了与needle的第一个字符匹配的字符,strstr函数会继续比较haystack中的后续字符和needle中的字符,直到找到一个不匹配的字符或者needle中的所有字符都匹配

    3. 如果找到了完全匹配的子字符串,strstr函数会返回指向该子字符串的指针

    4. 如果在haystack中找不到子字符串,或者needle是一个空字符串,则strstr函数会返回NULL

    1.1示例

    1. int main()
    2. {
    3. char arr1[] = "abcdef";
    4. char arr2[] = "cd";
    5. printf("%s", strstr(arr1, arr2));
    6. return 0;
    7. }

     如果找到了完全匹配的子字符串,strstr函数会返回指向该子字符串的指针,结果如下:

    1.2注意事项:

    strstr函数是区分大小写的,如果要进行大小写不敏感的字符串比较,可以使用其他函数 

    1.3模拟实现

    1. char* my_strstr(const char* a1, const char* a2)
    2. {
    3. char* cp = a1;
    4. char* str1 = a1;
    5. char* str2;
    6. while (*cp)
    7. {
    8. str1 = cp;
    9. str2 = a2;
    10. while (*str1&&*str2&&*str1 == *str2)
    11. {
    12. str1++;
    13. str2++;
    14. }
    15. if (*str2 == '\0')
    16. {
    17. return cp;
    18. }
    19. cp++;
    20. }
    21. return NULL;
    22. }
    23. int main()
    24. {
    25. char arr1[] = "abcdef";
    26. char arr2[] = "cd";
    27. printf("%s", my_strstr(arr1, arr2));
    28. return 0;
    29. }

     2.strtok()

    strtok是一个C标准库函数,用于将一个字符串分割成多个子字符串。它的原型如下:

    char * strtok (char *str ,  const char *delim);

    其中,str是要分割的字符串delim是用作分隔符的字符串。函数返回一个指向分割后的第一个子字符串的指针,如果没有更多的子字符串,则返回NULL

    strtok函数使用一个静态变量来保存当前的分割位置,因此在多次调用strtok时,需要将原始字符串传递给第一次调用,而后续的调用只需要传递NULL作为第一个参数

    • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
    • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记

     2.1示例

    1. int main()
    2. {
    3. char arr[] = "123@abc%ABC";
    4. char a[] = "@%";
    5. printf("%s\n", strtok(arr, a));
    6. /*printf("%s\n", strtok(NULL, a));*/
    7. return 0;
    8. }

     结果如下:

     

    1. int main()
    2. {
    3. char arr[] = "123@abc%ABC";
    4. char a[] = "@%";
    5. printf("%s\n", strtok(arr, a));
    6. printf("%s\n", strtok(NULL, a));
    7. printf("%s\n", strtok(NULL, a));
    8. return 0;
    9. }

     结果如下:

     充分利用性质可以写出这样的代码:

    1. int main()
    2. {
    3. char arr[] = "123@abc%ABC";
    4. char a[] = "@%";
    5. /*printf("%s\n", strtok(arr, a));
    6. printf("%s\n", strtok(NULL, a));
    7. printf("%s\n", strtok(NULL, a));*/
    8. for (char* ret = strtok(arr, a); ret != NULL;ret= strtok(NULL, a))
    9. {
    10. printf("%s\n", ret);
    11. }
    12. return 0;
    13. }

    2.2注意事项

    需要注意的是,strtok函数会修改原始字符串,将分隔符替换为NULL字符。如果需要保留原始字符串,可以使用副本进行分割操作 


     二.错误信息报告

    1.strerror()

    strerror是一个C标准库函数,用于将错误码转换为对应的错误信息字符串。它的原型如下:

    char * strerror( int errnum );

    其中,errnum是错误码。函数返回一个指向错误信息字符串的指针

    • errnum是一个整数类型的错误码,通常用于表示函数调用或操作的结果状态
    • errno是一个全局变量,用于存储最近一次发生的错误码。当函数调用或操作失败时,它们通常会设置errno为一个非零的错误码,以指示错误的类型

     1.1示例

    输出1~10分别代表的错误信息:

    1. int main()
    2. {
    3. for (int i = 1; i <= 10; i++)
    4. {
    5. printf("%s\n", strerror(i));
    6. }
    7. return 0;
    8. }

    结果如下:
     

    1.2注意事项:

    strerror函数返回的指针指向的是一个静态分配的字符串,因此在多线程环境下不是线程安全的


     三.内存操作函数

    1.memcpy()

    memcpy是一个标准C库函数,用于将一段内存区域的数据复制到另一段内存区域。它的函数原型如下:

    void *memcpy(void *dest, const void *src, size_t n);

    其中,dest是目标内存区域的指针,src是源内存区域的指针,n是要复制的字节数。

    memcpy函数将源内存区域的n个字节复制到目标内存区域中。如果源和目标区域重叠,memcpy函数的行为是未定义的。如果需要处理重叠区域的复制,可以使用memmove函数(下面介绍)

    这个函数在遇到 '\0' 的时候并不会停下来 

    1.1示例

    1. int main()
    2. {
    3. char src[] = "Hello, world!";
    4. char dest[20];
    5. memcpy(dest, src, strlen(src) + 1);
    6. printf("source string: %s\n", src);
    7. printf("copied string: %s\n", dest);
    8. return 0;
    9. }

    结果如下:

     

    1.2注意事项

    需要注意的是,memcpy函数不会自动添加字符串结束符\0,因此在复制字符串时需要将\0一起复制。在上面的示例中,strlen(src) + 1计算了源字符串的长度,并将其加1,以便复制\0 

    2.memmove()

    memmove是一个标准C库函数,用于将一段内存区域的数据复制到另一段内存区域,与memcpy函数类似。但是,memmove函数可以处理源和目标区域重叠的情况,而memcpy函数则不能

    memmove函数的函数原型如下:

    void *memmove(void *dest, const void *src, size_t n);

    其中,dest是目标内存区域的指针,src是源内存区域的指针,n是要复制的字节数。

    memmove函数将源内存区域的前n个字节复制到目标内存区域中。如果源和目标区域重叠,memmove函数会确保复制的结果是正确的,即使源和目标区域重叠。因此,memmove函数比memcpy函数更安全,但通常也更慢

     2.1示例

    1. int main()
    2. {
    3. char str[] = "123456";
    4. memmove(str,str+3,3);
    5. printf("%s\n", str);
    6. return 0;
    7. }

     结果如下:

     2.2注意事项:

    需要注意的是,memmove函数和memcpy函数一样,不会自动添加字符串结束符\0,因此在复制字符串时需要将\0一起复制

    3.memset()

    memset是一个用于设置内存块内容的函数。它可以将指定的内存块中的每个字节都设置为特定的值。

    memset函数的原型如下:

    void *memset(void *ptr, int value, size_t num);

    参数说明:

    • ptr:指向要设置的内存块的指针。
    • value:要设置的值,以整数形式提供。
    • num:要设置的字节数。

    memset函数将ptr指向的内存块的num个字节设置为value指定的值

     3.1示例

    1. int main()
    2. {
    3. char str[20] = { 0 };
    4. memset(str, 'A', 10);
    5. printf("%s\n", str);
    6. return 0;
    7. }

     结果如下:

     3.2注意事项:

    需要注意的是,memset函数是按字节进行设置的,因此对于非字符类型的数组,需要将value参数转换为相应的字节表示

     4.memcmp()

    memcmp函数用于比较两个内存区域的内容是否相同,其原型如下:

    int memcmp(const void *ptr1, const void *ptr2, size_t num);

    参数说明:

    • ptr1:指向第一个内存区域的指针。
    • ptr2:指向第二个内存区域的指针。
    • num:要比较的字节数。

    memcmp函数将ptr1指向的内存区域和ptr2指向的内存区域的前num个字节进行比较,返回值如下:

    • 如果两个内存区域相同,返回0。
    • 如果第一个内存区域小于第二个内存区域,返回负整数。
    • 如果第一个内存区域大于第二个内存区域,返回正整数

    4.1示例

    1. int main()
    2. {
    3. char str1[20] = "Hello, world!";
    4. char str2[20] = "Hello, world!";
    5. int result1 = memcmp(str1, str2, strlen(str1));
    6. printf("result = %d\n", result1);
    7. return 0;
    8. }

    结果如下:


     

    4.2注意事项:

    memcmp函数比较的是字节,因此对于非字符类型的数组,比较的结果可能与预期不同 

     


    好了各位,这次的内容就先整理到这里吧!下次按照学习计划就打了结构体的部分知识内容啦! 

  • 相关阅读:
    angular:HtmlElement的子节点有Shadow dom时奇怪的现象
    中加石墨再冲刺港交所上市:2022年初至今收入为零,陈东尧为CEO
    【Linux】题解:Linux环境基础开发工具——进度条
    Odoo:全球排名第一的免费开源PLM管理系统介绍
    js变量的重复声明问题总结
    Tensorflow 01(介绍)
    linux后台运行golang
    linux--LVS负载均衡 DR模式 rr
    【SPI读取外部Flash】使用逻辑分析仪来读取FLASH Device ID
    golang使用高阶函数优化业务功能
  • 原文地址:https://blog.csdn.net/qq_74415153/article/details/133652016