• 【濡白的C语言】部分string.h库函数的实现


    前言

            为帮助大家更好的理解C语言各个函数的含义,以及弄清他们的原理,因此尝试自己模拟试库函数对于大家的代码能力提升是非常有必要的。  

    目录b6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    strlen

    strcpy

    strcat

     strcmp

    strstr

    memcpy

     memmove


    strlenb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. int MyStrlen(const char* str)
    2. {
    3. int i = 0;
    4. for (i = 0; str[i] != 0; i++);
    5. return i;
    6. }

    函数传参是const char*类型,就保证了不会因为误操作改变了字符串原本的内容,循环的意思是,从0开始计数,如果不是'\0'的话就不执行任何操作,只有i++,然后到字符串结尾的时候跳出循环,此时 i 的大小就是字符串的长度。

    strcpyb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. void MyStrcpy(char* destion, const char* source)
    2. {
    3. assert(destion != NULL);
    4. assert(sorce != NULL);
    5. int i = 0;
    6. while (source[i] != 0)
    7. {
    8. destion[i] = source[i];
    9. i++;
    10. }
    11. destion[i] = source[i];
    12. }

    其中 assert 表示 destion和sorce不能是空指针,不然不可被修改或解引用。由于循环结束的标志是sorce到结尾,此时是不会进入循环的,也就是'\0'实际上没有被写入destion,因此在循环结束后手动在赋值一次,为destion添加上终止符。

    strcatb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. void MyStrcat(char* des, const char* sor)
    2. {
    3. assert(des != NULL);
    4. assert(sor != NULL);
    5. int m = 0, n = 0;
    6. for (m = 0; des[m]; m++);
    7. for (n = 0; sor[n]; n++)
    8. des[m + n] = sor[n];
    9. des[m + n] = sor[n];
    10. }

     类似于上面的strcpy函数,同样需要判断两个指针都不能是空指针,不然无法写入或者解引用,也需要在循环之外在此赋值一次加上’\0‘。

     strcmpb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. int MyStrcmp(const char* str1, const char* str2)
    2. {
    3. while (1)
    4. {
    5. if ((*str1) < (*str2))
    6. return -1;
    7. else if ((*str1) > (*str2))
    8. return 1;
    9. else if ((*str1) && (*str2) && ((*str1) == (*str2)))
    10. str1++, str2++;
    11. else
    12. return 0;
    13. }
    14. }

    可以分为四种情况,a<b,b<a,a = b且未结束, a = b且结束。采用死循环直接用return跳出整个函数。

    strstrb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. void getkmp(char* t, int* next)
    2. {
    3. int j, k, str = strlen(t);
    4. j = 0; k = -1;
    5. next[0] = -1;
    6. while (j < str - 1)
    7. {
    8. if (k == -1 || t[j] == t[k])
    9. {
    10. j++; k++;
    11. next[j] = k;
    12. }
    13. else
    14. {
    15. k = next[k];
    16. }
    17. }
    18. }
    19. int strStr(char* arr, char* arr2)
    20. {
    21. int m = 0, n = 0, str = strlen(arr), str2 = strlen(arr2);
    22. if (str2 == 0)
    23. return 0;
    24. else if (str < str2)
    25. return -1;
    26. int i[50000];
    27. getkmp(arr2, i);
    28. i[0] = 0;
    29. for (m = 0, n = 0; m < str;)
    30. {
    31. if (arr[m] == arr2[n])
    32. {
    33. m++, n++;
    34. }
    35. else
    36. {
    37. if (n == 0)
    38. m++;
    39. n = i[n];
    40. }
    41. if (n == str2)
    42. return m - str2;
    43. }
    44. return -1;
    45. }

     由于是字符串匹配,采用了kmp算法,时间复杂度上稍快,但是也可以自行尝试暴力解法,即时间复杂度O(m*n),比较字符串a,b的首字符,相同就进入循环,逐个判断,当不相同的时候,从头接着往后寻找相同的首字符,并再次开始比较,具体可参考另一篇文章:

    KMP算法_是小黄呀~的博客-CSDN博客_kmp算法

    memcpyb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. void MyMemcpy(char* str1, char* str2, int nums)
    2. {
    3. for (int i = 0; i < nums; i++)
    4. str1[i] = str2[i];
    5. }

     memmoveb6c641ff269a4c3ab1f0a1a6765ebf6a.gif

    1. void MyMemmove(char* str1, char* str2, int nums)
    2. {
    3. if (str1 - str2 < 0)
    4. for (int i = 0; i < nums; i++)
    5. str1[i] = str2[i];
    6. else
    7. for (; nums > 0; nums--)
    8. str1[nums - 1] = str2[nums - 1];
    9. }

     将两个函数放在一起,相对于memcpy,memmove仅多了一个判断两个指针位置的步骤,不同的位置对应不同的赋值顺序,这样就避免了可能出现的覆盖情况。

    还有很多库函数大家可以尝试模拟,例如比较经典的qsort函数,atio函数等,可以尝试完全按照库函数本身的返回值类型和传参模拟,这样才能更加深入地了解到函数一些设置的意义。

     

     

  • 相关阅读:
    【无标题】
    算法题整理(蓝桥 & leetcode)(待更新)
    CentOS 7 双网卡bond 网卡mac 相同的处理
    算法 顺时针旋转矩阵
    2009-2018年31省份旅游收入(入境、国内、总收入;第三产值;GDP)
    getid3 获取视频时长
    使用阿里云国际版应该避免哪些操作?
    【VSCode】SSH Remote 通过跳板机连开发机提示“bash行1 powershell未找到命令”
    CSS3新增特性(一)
    【【萌新的SOC学习之 VDMA 彩条显示实验之一】】
  • 原文地址:https://blog.csdn.net/qq_62306969/article/details/126314838