深入理解并模拟实现函数

简介: 深入理解并模拟实现函数

前言:

       我们前面已经学习了函数、指针等一系列知识,接下来,咱们一起来模拟实现strlen、qsort、strcpy、strcat、strcmp、strstr、memmove、memcpy、atoi,以及strncat、strncmp、strtok、strerror、memset、memcmp的使用。

一、使用并模拟实现qsort

       qsort可以对函数进行排序,使函数从无序变成有序。以下是官网解释:

          qsort函数也称之为快排。在确定好是降序还是升序后,经行快速排序,在所有排序中时间复杂度最低,效率更高。

       下面是用代码演示一下:

1. #include <stdio.h>      /* printf */
2. #include <stdlib.h>     /* qsort */
3. 
4. int values[] = { 40, 10, 100, 90, 20, 25 };
5. 
6. int compare(const void* a, const void* b)
7. {
8. return (*(int*)a - *(int*)b);
9. }
10. 
11. int main()
12. {
13. int n;
14. qsort(values, 6, sizeof(int), compare);
15. for (n = 0; n < 6; n++)
16. printf("%d ", values[n]);
17. return 0;
18. }

       运行结果如下:

        相信大家对此函数有了初步了解,那下面进行模拟实现(冒泡实现)。

1. #include<stdio.h>
2. #include<assert.h>
3. int cmp(const void* p1,const void* p2)
4. {
5.  return ((*(int*)p1) - (*(int*)p2));
6. }
7. void sweap(void* p1, void* p2, int sz)
8. {
9.  for (int i = 0; i < sz; i++)
10.   {
11.     int cmp = *((char*)p1+i);
12.     *((char*)p1 + i) = *((char*)p2 + i);
13.     *((char*)p2 + i) = cmp;
14.   }
15. }
16. void bubble(int* arr, int n, int sz, int(*cmp)(void*, void*))//使用void*为了适应各种指针类型
17. {
18. assert(arr);
19.   for (int i = 0; i < n-1; i++)
20.   {
21.     for (int j = 0; j < n - 1 - i; j++)
22.     {
23.       if (cmp((char*)arr + j * sz, (char*)arr + (j + 1) * sz) > 0)
24.       {
25.         sweap((char*)arr + j * sz, (char*)arr + (j + 1) * sz,sz);//使用char*能够访问到每个比特位
26.       }
27.     }
28.   }
29. }
30. int main()
31. {
32.   int arr[10] = { 1,2,3,8,9,4,5,1,3,10 };
33.   bubble(arr, sizeof(arr)/sizeof(arr[0]),sizeof(int), cmp);
34.   for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
35.   {
36.     printf("%d", arr[i]);
37.   }
38.   return 0;
39. }

二、使用模拟实现strlen

       strlen可以实现统计数组中元素个数(包括空格)。官网解释如下:

       字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包 含 '\0' )。

        参数指向的字符串必须要以 '\0' 结束。

       注意函数的返回值为size_t,是⽆符号的( 易错 )

        strlen的使⽤需要包含头⽂件

       使用代码如下:

1. /* strlen example */
2. #include <stdio.h>
3. #include <string.h>
4. 
5. int main ()
6. {
7. char szInput[256];
8. printf ("Enter a sentence: ");
9. gets (szInput);
10. printf ("The sentence entered is %u characters long.\n",(unsigned)strlen(szInput));
11. return 0;
12. }

       对其模拟如下:

1. #include<stdio.h>
2. //法一:使用计数器方式
3. my_strlen(char* arr)
4. {
5.  int count = 0;
6.  while (*arr != 0)
7.  {
8.    count++;
9.    arr++;
10.   }
11.   return count;
12. }
13. //法二:使用递归方式
14. int my_strlen(char* arr)
15. {
16.   if (*arr == '\0')
17.   {
18.     return 0;
19.   }
20.   else
21.     return 1 + my_strlen(arr + 1);
22. }
23. //法三:使用指针-指针方式
24. int my_strlen(char* arr)
25. {
26.   char* s = arr;
27.   while (*arr != '\0')
28.   {
29.     arr++;
30.   }
31.   return arr - s;
32. }
33. int main()
34. {
35.   char arr[] = "12345";
36.   int ret = my_strlen(arr);
37.   printf("%d", ret);
38.   return 0;
39. }

       以上三种方式供大家学习。

三、使⽤和模拟实现strcpy 函数

       strcpy可将一个字符串拷贝到一个数组中。官网解释如下:

       源字符串必须以 '\0' 结束。

       会将源字符串中的 '\0' 拷⻉到⽬标空间。

        ⽬标空间必须⾜够⼤,以确保能存放源字符串。

       ⽬标空间必须可修改。

       代码实现如下:

1. /* strcpy example */
2. #include <stdio.h>
3. #include <string.h>
4. 
5. int main()
6. {
7.  char str1[] = "Sample string";
8.  char str2[40];
9.  char str3[40];
10.   strcpy(str2, str1);
11.   strcpy(str3, "copy successful");
12.   printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
13.   return 0;
14. }

       模拟实现如下:

1. #include<stdio.h>
2. char* my_strcpy(char* dest, const char* src)
3. {
4.  char* str = dest;
5.  while (*dest++ = *src++)
6.  {
7.    ;
8.  }
9.  return str;
10. }
11. int main()
12. {
13.   char arr1[] = "123456";
14.   char arr2[] = "abcdef";
15.   my_strcpy(arr1, arr2);
16.   printf("%s", arr1);
17.   return 0;
18. }

四、使用并模拟实现strcat 函数

         strcat函数是字符串追加函数,也就是在字符串后面追加另一个字符串。官网解释如下:

       使用 该函数代码如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str[80];
7.  strcpy(str, "these ");
8.  strcat(str, "strings ");
9.  strcat(str, "are ");
10.   strcat(str, "concatenated.");
11.   puts(str);
12.   return 0;
13. }

       源字符串必须以 '\0' 结束。

       ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。

       ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。

       ⽬标空间必须可修改。

       模拟实现如下:

1. #include<stdio.h>
2. char* my_strcat(char* destination, const char* source)
3. {
4.  char* ret = destination;
5.  while (*destination)
6.  {
7.    destination++;
8.  }
9.  while (*destination++ = *source++)
10.   {
11.     ;
12.   }
13.   return ret;
14. }
15. int main()
16. {
17.   char arr1[] = "hello";
18.   char arr2[] = " world";
19.   my_strcat(arr1,arr2);
20.   printf("%s", arr1);
21.   return 0;
22. }

五、使用并模拟实现strcmp函数

       strcmp函数是C语言中字符串比较函数,用于比较两个字符串的大小。官网解释如下:

       如果相等则,返回零,若str>str2,则大于零,反之小于零。

       使用该函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6. char key[] = "apple";
7. char buffer[80];
8. do
9.     {
10. printf("Guess my favorite fruit? ");
11. fflush(stdout);
12. scanf("%79s", buffer);
13.     } while (strcmp(key, buffer) != 0);
14. puts("Correct answer!");
15. return 0;
16. }

        模拟实现该函数如下:

1. #include<stdio.h>
2. #include<assert.h>
3. int my_strcmp(const char* str1, const char* str2)
4. {
5.  assert(str1 && str2);
6.  while (*str1++ == *str2++)
7.  {
8.    if (*str1 == *str2)
9.    {
10.       return 0;
11.     }
12.   }
13.   return *str1 - *str2;
14. }
15. int main()
16. {
17.   char arr1[] = "abcd";
18.   char arr2[] = "ace";
19.   int ret = my_strcmp(arr1, arr2);
20.   if (ret > 0)
21.   {
22.     printf("arr1>arr2\n");
23.   }
24.   else if (ret < 0)
25.   {
26.     printf("arr1<arr2\n");
27.   }
28.   else
29.   {
30.     printf("arr1=arr2\n");
31.   }
32.   return 0;
33. }

六、使用并模拟实现strstr函数

       strstr函数是在字符串str1中查找是否含有字符串str2,如果存在,返回str2在str1中第一次出现的地址;否则返回NULL。官网解释如下:

       对其使用代码如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6. char str[] = "This is a simple string";
7. char* pch;
8.     pch = strstr(str, "simple");
9. if (pch != NULL)
10. strncpy(pch, "sample", 6);
11. puts(str);
12. return 0;
13. }

       Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1. (函数返回字符串str2在字符串str1中第⼀次出现的位置)。

        The matching process does not include the terminating null-characters, but it stops there.(字符 串的⽐较匹配不包含 \0 字符,以 \0 作为结束标志)。

        模拟实现该函数如下:

1. #include<stdio.h>
2. char* my_strstr(const char* str1, const char* str2)
3. {
4.  char* p = (char*)str1;
5.  if (!*str2)
6.  {
7.    return str1;
8.  }
9.  while (*p)
10.   {
11.     char* s1 = p;
12.     char* s2 = (char*)str2;
13.     while (*s1 && *s2 && !(*s1 - *s2))
14.     {
15.       s1++;
16.       s2++;
17.     }
18.     if (*s2)
19.     {
20.       return p;
21.     }
22.     p++;
23.   }
24.   return NULL;
25. }
26. int main()
27. {
28.   char arr1[] = "This is a simple string";
29.   char arr2[] = "simple";
30.   my_strstr(arr1, arr2);
31.   printf(arr2);
32.   return 0;
33. }

七、使用strtok函数

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

        sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合

       第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记。

        strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容 并且可修改。)

       strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。

        strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记。

        如果字符串中不存在更多的标记,则返回 NULL 指针。

       官网解释如下:

       使用该函数:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str[] = "- This, a sample string.";
7.  char* pch;
8.  printf("Splitting string \"%s\" into tokens:\n", str);
9.  pch = strtok(str, " ,.-");
10.   while (pch != NULL)
11.   {
12.     printf("%s\n", pch);
13.     pch = strtok(NULL, " ,.-");
14.   }
15.   return 0;
16. }

八、使用strerror函数

       strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。 在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明 的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应 的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

        官网解释如下:

       代码使用函数:

1. #include <stdio.h>
2. #include <string.h>
3. #include <errno.h>
4. 
5. int main()
6. {
7.  FILE* pFile;
8.  pFile = fopen("unexist.ent", "r");
9.  if (pFile == NULL)
10.     printf("Error opening file unexist.ent: %s\n", strerror(errno));
11.   return 0;
12. }

九、使用strncmp函数

       strcmp函数与strncmp函数从函数名看来基本一样,确实,它们确实大体上相同,区别为:n确定了比较多少个元素,官网解释如下:

       其返回值也是相同。         对其使用如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
7.  int n;
8.  puts("Looking for R2 astromech droids...");
9.  for (n = 0; n < 3; n++)
10.     if (strncmp(str[n], "R2xx", 2) == 0)
11.     {
12.       printf("found %s\n", str[n]);
13.     }
14.   return 0;
15. }

十、使用strncat函数

       strncat函数与strcat函数的区别也类似与上述函数,只不过区别是拼接字节的个数仅此而已。官网解释如下:

       使用该函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str1[20];
7.  char str2[20];
8.  strcpy(str1, "To be ");
9.  strcpy(str2, "or not to be");
10.   strncat(str1, str2, 6);
11.   puts(str1);
12.   return 0;
13. }

十一、使用并模拟实现memcpy函数

        memcpy函数是C语言中内存函数,其功能和strcpy函数类似,以下为官网解释:

       函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。

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

       如果source和destination有任何的重叠,复制的结果都是未定义的。

       对其使用结果如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. struct {
5.  char name[40];
6.  int age;
7. } person, person_copy;
8. 
9. int main()
10. {
11.   char myname[] = "Pierre de Fermat";
12. 
13.   /* using memcpy to copy string: */
14.   memcpy(person.name, myname, strlen(myname) + 1);
15.   person.age = 46;
16. 
17.   /* using memcpy to copy structure: */
18.   memcpy(&person_copy, &person, sizeof(person));
19. 
20.   printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
21. 
22.   return 0;
23. }

        对其模拟代码如下:

1. #include<stdio.h>
2. #include<assert.h>
3. void* my_memcpy(void* destination, const void* source, size_t num)
4. {
5.  assert(destination && source);
6.  void* p = destination;
7.  while (num--)
8.  {
9.    *(char*)destination = *(char*)source;
10.     destination = (char*)destination + 1;
11.     source = (char*)source + 1;
12.   }
13.   return (p);
14. }
15. int main()
16. {
17.   int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
18.   int arr2[20] = { 0 };
19.   my_memcpy(arr2, arr1,40);
20.   for (int i = 0; i < 10; i++)
21.   {
22.     printf("%d ", arr2[i]);
23.   }
24.   return 0;
25. }

十二、使用并模拟实现memmove函数

       memmove函数也是内存函数,它的作用是可以实现对目标字符串的拷贝并放入指定位置。官网解释如下:

       和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。

       如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。

        试用该函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str[] = "memmove can be very useful......";
7.  memmove(str + 20, str + 15, 11);
8.  puts(str);
9.  return 0;
10. }

       模拟实现如下:

1. #include<stdio.h>
2. #include<assert.h>
3. void* my_memmove(void* dest, const void* sour, size_t num)
4. {
5.  void* p = dest;
6.  if (dest < sour)
7.  {
8.    while (num--)
9.    {
10.       *(char*)dest = *(char*)sour;
11.       dest = (char *)dest+1;
12.       sour = (char*)sour + 1;
13.     }
14.   }
15.   else
16.   {
17.     dest = (char*)dest + num - 1;
18.     sour = (char*)sour + num - 1;
19. 
20.     while (num--)
21.     {
22.       *(char*)dest = *(char*)sour;
23.       dest = (char*)dest - 1;
24.       sour = (char*)sour - 1;
25.     }
26.   }
27.   return p;
28. }
29. int main()
30. {
31.   char str[] = "memmove can be very useful......";
32.   my_memmove(str + 20, str + 15, 11);
33.   puts(str);
34.   return 0;
35. }

十三、使用memset函数

       memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。官网解释如下:

       使用函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char str[] = "almost every programmer should know memset!";
7.  memset(str, '-', 6);
8.  puts(str);
9.  return 0;
10. }

十四、使用 memcmp函数

       该函数即为比较函数与上文strncmp函数类似。官网解释如下:

       使用该函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. 
4. int main()
5. {
6.  char buffer1[] = "DWgaOtP12df0";
7.  char buffer2[] = "DWGAOTP12DF0";
8. 
9.  int n;
10. 
11.   n = memcmp(buffer1, buffer2, sizeof(buffer1));
12. 
13.   if (n > 0)
14.   {
15.     printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
16.   }
17.   else if (n < 0)
18.   {
19.     printf("'%s' is less than '%s'.\n", buffer1, buffer2);
20.   }
21.   else
22.   {
23.     printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
24.   }
25.   return 0;
26. }

十五、使用并模拟实现atoi函数

它的功能:

解析将其内容解释为整数的 C 字符串,该整数作为 类型的值返回。

该函数首先根据需要丢弃尽可能多的空格字符(如 ),直到找到第一个非空格字符。然后,从此字符开始,取一个可选的首字母加号或减号,后跟尽可能多的 10 进制数字,并将它们解释为数值。

字符串可以在构成整数的字符之后包含其他字符,这些字符将被忽略,并且对此函数的行为没有影响。

如果 中的第一个非空格字符序列不是有效的整数,或者由于为空或仅包含空格字符而不存在此类序列,则不执行转换并返回零。

        官网解释:

       使用该函数如下:

1. #include <stdio.h>
2. #include <string.h>
3. int main()
4. {
5.  int i;
6.  char buffer[256];
7.  printf("Enter a number: ");
8.  fgets(buffer, 256, stdin);
9.  i = atoi(buffer);
10.   printf("The value entered is %d. Its double is %d.\n", i, i * 2);
11.   return 0;
12. }

       模拟实现如下:

1. #include<stdio.h>
2. #include<assert.h>
3. #include<ctype.h>
4. #include<stdlib.h>
5. enum State
6. {
7.  INVAILD,
8.  VAILD
9. }a;
10. int my_atoi(const char* str)
11. {
12.   assert(str);
13.   if (*str == '\0')
14.   {
15.     return 0;
16.   }
17.   while (isspace(*str))
18.   {
19.     str++;
20.   }
21.   int flag = 1;
22.   if (*str == '+')
23.   {
24.     flag = 1;
25.     str++;
26.   }
27.   if (*str == '-')
28.   {
29.     flag = -1;
30.     str++;
31.   }
32.   long long ret = 0;
33.   while (*str != '\0')
34.   {
35.     if (isdigit(*str))
36.     {
37.       ret = ret * 10 + flag * (*str - '0');
38.       if (ret > INT_MAX)
39.       {
40.       return INT_MAX;
41.       }
42.       if (ret < INT_MIN)
43.       {
44.       return INT_MIN;
45.       }
46.     }
47.     else
48.     {
49.        (int)ret;
50.     }
51.     str++;
52.   }
53.   if (*str == '\0')
54.   {
55.      a =VAILD;
56.   }
57.   return (int)ret;
58. }
59. int main()
60. {
61.   char arr[20] = "-123456";
62.   int ret = my_atoi(arr);
63.   if (a == VAILD)
64.   {
65.     printf("合法转化:%d\n", ret);
66.   }
67.   else if(a == INVAILD)
68.   {
69.     printf("非法转化:%d\n", ret);
70.   }
71.   return 0;
72. }

完!

相关文章
|
7月前
函数的模拟实现
函数的模拟实现
49 0
|
7月前
模拟队列训练
模拟队列训练
37 0
|
25天前
|
前端开发 JavaScript
模拟 new 的实现
模拟 `new` 实现是指在 JavaScript 中,通过自定义函数来模拟内置的 `new` 操作符的行为,以便更好地理解其工作原理和对象构造过程。这种方式通常涉及创建一个新对象、绑定原型链、执行构造函数等步骤。
|
7月前
函数的模拟实现1
函数的模拟实现1
60 0
|
C语言
内存函数及其模拟实现
内存函数及其模拟实现
|
Python
抽卡程序模拟
抽卡程序模拟
143 0
内存函数的使用和模拟实现
那么今天我要分享的是内存函数,为什么我会给大家分享这个呢?或者说,内存函数的作用是什么呢?有了字符函数就行了,为什么还会有内存函数呢?那么我们就先来看看字符函数和字符串函数的局限性。字符函数和字符串函数,看见这个名字我们应该就可以知道这个函数的操作对象是什么了,没错,字符函数和字符串函数是操作字符和字符串的,但是平常生活中我们遇到的可不止有字符串,所以这时候就出现了内存函数,它的好处是:可以操作任意类型的数据,这样就极大的方便了我们了我们的生活。接下来我们就来看看这些内存函数是如何使用以及自己来模拟实现它。
|
SQL 监控 前端开发
模拟数据在实际场景中的应用
模拟数据在实际场景中的应用
178 0
模拟数据在实际场景中的应用
|
Go
UCF2016-g2g c u l8r(模拟)
UCF2016-g2g c u l8r(模拟)
83 0