为帮助大家更好的理解C语言各个函数的含义,以及弄清他们的原理,因此尝试自己模拟试库函数对于大家的代码能力提升是非常有必要的。
目录
- int MyStrlen(const char* str)
- {
- int i = 0;
- for (i = 0; str[i] != 0; i++);
- return i;
- }
函数传参是const char*类型,就保证了不会因为误操作改变了字符串原本的内容,循环的意思是,从0开始计数,如果不是'\0'的话就不执行任何操作,只有i++,然后到字符串结尾的时候跳出循环,此时 i 的大小就是字符串的长度。
- void MyStrcpy(char* destion, const char* source)
- {
- assert(destion != NULL);
- assert(sorce != NULL);
- int i = 0;
- while (source[i] != 0)
- {
- destion[i] = source[i];
- i++;
- }
- destion[i] = source[i];
- }
其中 assert 表示 destion和sorce不能是空指针,不然不可被修改或解引用。由于循环结束的标志是sorce到结尾,此时是不会进入循环的,也就是'\0'实际上没有被写入destion,因此在循环结束后手动在赋值一次,为destion添加上终止符。
- void MyStrcat(char* des, const char* sor)
- {
- assert(des != NULL);
- assert(sor != NULL);
- int m = 0, n = 0;
- for (m = 0; des[m]; m++);
- for (n = 0; sor[n]; n++)
- des[m + n] = sor[n];
- des[m + n] = sor[n];
- }
类似于上面的strcpy函数,同样需要判断两个指针都不能是空指针,不然无法写入或者解引用,也需要在循环之外在此赋值一次加上’\0‘。
- int MyStrcmp(const char* str1, const char* str2)
- {
- while (1)
- {
- if ((*str1) < (*str2))
- return -1;
- else if ((*str1) > (*str2))
- return 1;
- else if ((*str1) && (*str2) && ((*str1) == (*str2)))
- str1++, str2++;
- else
- return 0;
- }
- }
可以分为四种情况,a<b,b<a,a = b且未结束, a = b且结束。采用死循环直接用return跳出整个函数。
- void getkmp(char* t, int* next)
- {
- int j, k, str = strlen(t);
- j = 0; k = -1;
- next[0] = -1;
- while (j < str - 1)
- {
- if (k == -1 || t[j] == t[k])
- {
- j++; k++;
- next[j] = k;
- }
- else
- {
- k = next[k];
- }
- }
- }
-
- int strStr(char* arr, char* arr2)
- {
- int m = 0, n = 0, str = strlen(arr), str2 = strlen(arr2);
- if (str2 == 0)
- return 0;
- else if (str < str2)
- return -1;
- int i[50000];
- getkmp(arr2, i);
- i[0] = 0;
- for (m = 0, n = 0; m < str;)
- {
- if (arr[m] == arr2[n])
- {
- m++, n++;
- }
- else
- {
- if (n == 0)
- m++;
- n = i[n];
- }
- if (n == str2)
- return m - str2;
- }
- return -1;
- }
由于是字符串匹配,采用了kmp算法,时间复杂度上稍快,但是也可以自行尝试暴力解法,即时间复杂度O(m*n),比较字符串a,b的首字符,相同就进入循环,逐个判断,当不相同的时候,从头接着往后寻找相同的首字符,并再次开始比较,具体可参考另一篇文章:
- void MyMemcpy(char* str1, char* str2, int nums)
- {
- for (int i = 0; i < nums; i++)
- str1[i] = str2[i];
- }
- void MyMemmove(char* str1, char* str2, int nums)
- {
- if (str1 - str2 < 0)
- for (int i = 0; i < nums; i++)
- str1[i] = str2[i];
- else
- for (; nums > 0; nums--)
- str1[nums - 1] = str2[nums - 1];
- }
将两个函数放在一起,相对于memcpy,memmove仅多了一个判断两个指针位置的步骤,不同的位置对应不同的赋值顺序,这样就避免了可能出现的覆盖情况。
还有很多库函数大家可以尝试模拟,例如比较经典的qsort函数,atio函数等,可以尝试完全按照库函数本身的返回值类型和传参模拟,这样才能更加深入地了解到函数一些设置的意义。