• 字符串函数的模拟实现


    引言:对于字符串来说,我们通常想要对其完成各种各样的目的,不管是排序还是查找都是最普遍的功能,而我们的C语言中也包含着一系列函数是为了实现对字符串的一些功能,今天我们就来介绍他们。


    strlen函数:

    求字符串的长度(也就是求一个字符串的'\0'前面有多少个字符)

    1. #include
    2. #include
    3. int main(){
    4. char* str = "abcdef";
    5. int b = strlen(str);
    6. printf("%d\n", b);
    7. return 0;
    8. }

    看一个特性:我们可以看到这个代码,正常来说结果是-3应该输出的是"<"但是结果是">=",

    这是因为strlen函数返回的是无符号整型(size_t),两个无符号整型相减还是无符号整形,那么负3就变成了一个很大的正数,如果想要正常的效果我们可以强制转化为(int)。

    这个就是strlen最常用的,用来求一个字符串的长度,那么我们是否可以不用库函数,自己模拟一个strlen呢🤔
    1. #include
    2. #include
    3. //方法一:计数法
    4. size_t my_strlen1(char* str) {
    5. int count = 0;
    6. while (*str) {
    7. count++;
    8. str++;
    9. }
    10. return count;
    11. }
    12. int main(){
    13. char* str = "abcdef";
    14. int c = my_strlen1(str);
    15. printf("%d\n", c);
    16. return0;
    17. }

    方法一:计数法,利用for循环,用count计数,当str遇到'\0'的时候循环结束,跳出循环,返回count的值。

    1. #include
    2. #include
    3. //方法二:递归法
    4. size_t my_strlen2(char* str) {
    5. if (*str == '\0')
    6. return 0;
    7. else return 1+my_strlen2(str+1);
    8. }
    9. int main() {
    10. char* str = "abcdef";
    11. int d = my_strlen2(str);
    12. printf("%d\n", d);
    13. return 0;
    14. }

     方法二:递归法,利用递归思想,当没有遇到'\0'的时候,就再次调用该函数,直到str遇到'\0',返回0,然后依次再重新返回,就计算出了字符串的长度。

    1. #include
    2. #include
    3. //方法三:指针-指针
    4. size_t my_strlen3(char* str) {
    5. char* p = str;
    6. while (*p != '\0') {
    7. p++;
    8. }
    9. return p - str;
    10. }
    11. int main(){
    12. char* str = "abcdef";
    13. int e = my_strlen3(str);
    14. printf("%d\n", e);
    15. return 0;
    16. }

    方法三:指针-指针,我们先将字符串的首元素地址记为str,再将首元素地址传给p,利用while循环找到最后一个元素的地址,当(结束地址-首元素地址)即为字符串长度。

     可以看我们四种方法的运行结果,都是可以正确的求出字符串‘acbdef的长度.

    strcpy函数:

    1. #include
    2. #include
    3. int main(){
    4. char arr1[20] = { 0 };
    5. char arr2[] = "Hello";
    6. strcpy(arr1, arr2);
    7. printf("%s\n", arr1);
    8. return 0;
    9. }

    这个函数的作用就是将arr2中的字符串拷贝到arr1中。那么我们该如何对他进行模拟实现呢🤔

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. char* my_strcpy(char* dest, const char* src) {
    5. char* ret = dest;
    6. while (*dest++ = *src++)
    7. {
    8. ;
    9. }
    10. return ret;
    11. }
    12. int main(){
    13. char arr1[20] = { 0 };
    14. char arr2[] = "Hello";
    15. //strcpy(arr1, arr2);
    16. my_strcpy(arr1, arr2);
    17. printf("%s\n", arr1);
    18. return 0;
    19. }

     我们先将两个数组的首元素地址传给函数,因为最终要返回起始地址,所以先将dest给ret,然后运用while循环将src的每一项解引用后赋给dest,然后后置++再寻找下一个元素,直到src元素找到了'\0',然后循环跳出,返回起始地址ret。

    我们把arr1打印出来可以看到确实是成功拷贝。 

    strcmp函数:

    比较的结果是:
    如果str1>str2那么就返回一个>0的数 
    如果str1
    如果str1=str2那么就返回0
    1. #include
    2. #include
    3. int main() {
    4. char arr1[] = { "abc" };
    5. char arr2[] = { "abdef" };
    6. int a = strcmp(arr1, arr2);
    7. if (a > 0) printf(">=");
    8. else printf("<");
    9. return 0;
    10. }

    这是一个简单的例子,因为d的ASC的值比c的ASC的值大,所以arr1

    那么我们来模拟实现实现一下这个函数

    1. #include
    2. #include
    3. int my_strcmp(const char* dest, const char* src){
    4. while (*dest == *src) {
    5. if (*dest == 0) return 0;
    6. dest++;
    7. src++;
    8. }
    9. if (*dest > *src)
    10. return 1;
    11. else return -1;
    12. }
    13. int main() {
    14. char arr1[] = { "abc" };
    15. char arr2[] = { "abdef" };
    16. int a = my_strcmp(arr1, arr2);
    17. if (a > 0) printf(">=");
    18. else printf("<");
    19. return 0;
    20. }

     首先,还是一样,先传值然后依旧是运用我们的while循环来进行遍历以及交换,当其中一个已经遍历完之后,会跳出while循环,然后开始判断当前元素谁大谁小,然后根据大小返回大于零还是小于零的数。

    strcat函数:

    1. #include
    2. #include
    3. int main() {
    4. char arr1[20] = { "abc"};
    5. char arr2[] = { "def" };
    6. //库函数自带的strcat
    7. strcat(arr1, arr2);
    8. printf("%s\n", arr1);
    9. return 0;
    10. }

     值得注意的是:

    1、目标空间必须足够大,并且可以修改

    2、目标空间中必须有\0,以便能够找到目标空间的末尾

    3、源字符串中也得有\0,拷贝的时候要拷过去

    那么我们如何对这个函数进行模拟实现呢🤔

    1. #include
    2. #include
    3. char* my_strcat(char* dest, char* src) {
    4. char* ret = dest;
    5. assert(dest && src);
    6. while (*dest != '\0') {
    7. dest++;
    8. }
    9. while (*dest++ = *src++) {
    10. ;
    11. }
    12. return ret;
    13. }
    14. int main() {
    15. char arr1[20] = { "abc"};
    16. char arr2[] = { "def" };
    17. my_strcat(arr1, arr2);
    18. printf("%s\n", arr1);
    19. return 0;
    20. }

     依然是传参,然后用第一个while循环找到目标空间中的\0然后,跳出循环,此时dest指向目标函数的末尾,然后进入第二个循环,src开始给dest进行赋值,直到src遇到\0,跳出循环,返回目标函数的起始地址,完成追加。

    strstr函数: 

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. int main() {
    5. char arr1[] = { "abcdefghi" };
    6. char arr2[] = { "def" };
    7. char* ret = strstr(arr1, arr2);
    8. if (ret == NULL) {
    9. printf("找不到");
    10. }
    11. else printf("%s", ret);
    12. return 0;
    13. }

    strstr是字符串查找函数,我们给函数传两个字符串的时候,他会拿源函数去和目标函数进行匹配,如果目标函数中有原函数那么,就返回段函数的起始地址,如果找不到,那么就会返回NULL

    那么我们该如何模拟实现这一函数呢🤔

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. const char* my_strstr(const char* str1, const char* str2) {
    6. const char* sp;
    7. const char* s1;
    8. const char* s2;
    9. assert(str1 && str2);
    10. if (*str2 == '\0') {
    11. return str1;
    12. }
    13. sp = str1;
    14. while (*sp) {
    15. s1 = sp;
    16. s2 = str2;
    17. while (*str1 && *str2 && *s1 == *s2) {
    18. s1++;
    19. s2++;
    20. }
    21. if (*s2 == '\0')
    22. return sp;
    23. sp++;
    24. }
    25. return NULL;
    26. }
    27. int main() {
    28. char arr1[] = { "abcdefghi" };
    29. char arr2[] = { "def" };
    30. char* ret = my_strstr(arr1, arr2);
    31. if (ret == NULL) {
    32. printf("找不到");
    33. }
    34. else printf("%s", ret);
    35. return 0;
    36. }

     可以看到,我们模拟实现的函数成功的查找到了目标函数中的def,并且返回了找到它的起始位置。那么具体的实现我来详细的讲解一下。 

    如图,我们用s1和s2进行比较,
    1️⃣如果两个相同就各自+1比较下一个,那么按照这样进行下去,当str2为0的时候,就证明已经找到了,如果str1已经为0,str2还没有为0那么就证明,str1里找不到str2。
    2️⃣如果两个不同就sp++,然后sp再赋值给s1,这样就不会使得s1一直向前++而找不到原来的位置了,s2也是一样,当sp赋值给s1的时候,str2也同时赋值给s2,让s2能回到起始位置。
    这样一直对比下去,直到s1或s2指向0,函数结束。那我们这个函数的模拟就算实现了,但是其实这是个笨方法,效率不高,如果大家感兴趣的话,可以去了解了解kmp算法。

    strerror函数:

    是用来打印错误码的函数

    strtok函数:

    是一个奇怪的函数:是用来将一段字符串进行分割的函数

    例如:

    haohao@xue.xi   // @ .

    192.168.101.23    //IP地址,点分十进制

    (IP地址本来是一个无符号的整数,这种整数不方便记忆,所以将这个整数转换成点分十进制的表示方式)

    1. #include
    2. #include
    3. int main() {
    4. char arr[] = "haohao@xuexi@tiantian.xiangshang";
    5. char* p = "@.";
    6. char* s = NULL;
    7. for (s = strtok(arr, p); s != NULL; s = strtok(NULL, p)) {
    8. printf("%s\n",s);
    9. }
    10. return 0;
    11. }

    我们这里可以看到,strtok将arr里的字符串给分隔开了,这个函数可以把指定参数替换成'\0',这样就可以将那些干扰的字符给去掉,并将其一一打印出来了。

    值得注意的是:这个函数每次只能将其一段一段的切割开,所以首次调用的时候需要把待切割字符串的首地址传过去,如果要再次调用的话,则只需要传一个NULL地址过去,函数便会直接从上一次切割的地方开始从后切割。 

     好了,今天我就给大家分享到这里,感谢大家的观看!!!

  • 相关阅读:
    初阶牛之牛客网刷题集(1)
    线程的概念
    Ubuntu16.04 设置静态 ip
    怎么截取视频做gif动图?手把手教你视频在线转gif制作
    Spring Boot获取客户端的IP地址
    C++ map和set
    优秀的测试/开发程序员,是怎样修炼的?步步为营地去执行......
    level2行情接口十档行情快照如何去运用?
    Linux—vmstat命令详解
    图论学习总结
  • 原文地址:https://blog.csdn.net/2301_77125473/article/details/133578848