1.11 memcpy
void * memcpy ( void * destination, const void * source, size_t num );
(1)函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
(2)这个函数在遇到 '\0' 的时候并不会停下来。
(3)如果source和destination有任何的重叠,复制的结果都是未定义的。如果destination在source的后面,就可能会导致刚改变的destination的内容,又变成了source. 就会导致重复。这种情况建议使用memmove,就不会发生。
代码展示:
1. #include <stdio.h> 2. int main() 3. { 4. char arr1[] = "sjhjcd"; 5. char arr2[50] = { 0 }; 6. strcpy(arr2, arr1);//拷贝字符串 7. 8. int arr3[] = { 1, 2,3,4,5,6,7 }; 9. int arr4[5] = { 0 }; 10. memcpy(arr4, arr3, 20);//这个什么都可以拷贝,不确定拷贝什么 11. int i = 0; 12. for (i = 0; i < 5; i++) 13. { 14. printf("%d ", arr4[i]); 15. } 16. return 0; 17. }
C语言只要求memcpy能拷贝不重叠的的内存空间就足够了,memmove去处理那些重叠的内存空间。但是VS 的memcpy可以处理重叠的内存拷贝,也可以处理不重叠的内存拷贝。
1.12 memmove
void * memmove ( void * destination, const void * source, size_t num );
(1)和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
(2)如果源空间和目标空间出现重叠,就得使用memmove函数处理。
memmove 也可以处理不重叠的。
1.13 memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
(1)比较从ptr1和ptr2指针开始的num个字节
(2)返回值如下:
比较的是字节,相等的话,返回0。 比较的是ASCII值。
1.14 memset
代码展示:
1. #include <stdio.h> 2. int main() 3. { 4. char arr[20] = { 0 }; 5. memset(arr, 'x', 10); 6. return 0; 7. }
以字节为单位改。
二 库函数的模拟实现
2.1 模拟实现strlen
1 计数器的方法
1. #include <stdio.h> 2. #include <assert.h> 3. int my_strlen(const char* str) 4. { 5. assert(str); 6. int count = 0; 7. while (*str != '\0') 8. { 9. count++; 10. str++; 11. } 12. return count; 13. } 14. int main() 15. { 16. int len = 0; 17. len = my_strlen("abcdefg");//传递给my _strlen的是字符'a'的地址 18. printf("%d", len); 19. return 0; 20. }
\0 的ASCII码值是 0 ,一个表示字符串结束的标志,这是一个转义字符,整体视为一个字符,在内存中的存储为0000 0000
字符在内存中是以ASCII码值对应的二进制的补码存在的(8位)
2.2 模拟实现strcpy
代码展示:
1. #include <stdio.h> 2. #include <assert.h> 3. char* my_strcpy(char* a, const char* b) 4. { 5. assert(a && b); 6. char* ret = a; 7. while (*a++ = *b++)//++的优先级大于*的优先级 8. { 9. ; 10. } 11. return ret; 12. } 13. 14. int main() 15. { 16. char arr1[20] = { 0 }; 17. char arr2[] = "hello"; 18. printf("%s\n", my_strcpy(arr1, arr2));//函数的链式访问 19. return 0; 20. }
尽量不要返回局部变量的地址(调用的那个函数,里面的局部变量,使用完就可能被销毁了,地址指向的局部变量的值,可能就变了),而不是局部变量。
2.3 模拟实现strcat
代码展示:
1. #include <stdio.h> 2. #include <assert.h> 3. char* my_strcat(char* dest, const char* src) 4. { 5. char* ret = dest; 6. assert(dest && src); 7. while (*dest) 8. { 9. dest++; 10. } 11. while (*dest++ = *src++) 12. { 13. ; 14. } 15. return ret; 16. } 17. int main() 18. { 19. char arr1[30] = "hello"; 20. char arr2[] = "world"; 21. my_strcat(arr1, arr2); 22. printf("%s\n", arr1); 23. return 0; 24. }
思路:(1)找到目标空间中的\0 (2)追加字符
everyting——搜索strcat——右击 打开路径
2.4 模拟实现strstr
代码展示:
1. #include <stdio.h> 2. #include <assert.h> 3. char* my_strstr(const char* str1, const char* str2) 4. { 5. assert(str1 && str2); 6. if (*str2 == '\0') 7. { 8. return (char*)str1;//(const char* 和char*还是不同的) 9. } 10. //当第一个字符出现匹配,后续字母中出现不匹配的时候,字符串的地址要回到出现匹配的第一个字符,的下一个字符的地址, 11. //所以尽可能不要直接用str1和str2,而是间接的使用 12. const char* s1 = str1; 13. const char* s2 = str2; 14. const char* s3 = str1;//遇到匹配的第一个字符前一直在+1 15. while (*s3)//在这个循环里,s3一直在+1,一直到s3遇到\0 ,while结束 16. { 17. s1 = s3; 18. s2 = str2; 19. while (*s1 != '\0' && *s2 != '\0' && * s1 == *s2) 20. { 21. s1++; 22. s2++; 23. } 24. if (*s2 == '\0') 25. return (char*)s3; 26. s3++; 27. } 28. return NULL; 29. } 30. int main() 31. { 32. char arr1[] = "abcdabcd"; 33. char arr2[] = "A"; 34. char* ret = my_strstr(arr1, arr2); 35. if (ret == NULL) 36. printf("找不到"); 37. else 38. printf("%s\n", ret); 39. return 0; 40. }
2.5 模拟实现strcmp
代码展示:
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 == '\0') 9. { 10. return 0; 11. } 12. str1++; 13. str2++; 14. } 15. if (*str1 > *str2) 16. return 1; 17. else 18. return -1; 19. } 20. int main() 21. { 22. char arr1[] = "abc"; 23. char arr2[] = "abcd"; 24. int ret = my_strcmp(arr1, arr2); 25. printf("%d", ret); 26. return 0; 27. }
"abcd" 和"abc"比较,是1 因为,第一个字符串是d的ASCII,后一个字符串是'\0'的ascii,所以是1.
2.6 模拟实现memcpy
代码展示:
1. #include <stdio.h> 2. #include <assert.h> 3. void* my_memcpy(void* dest, const void* src, size_t num) 4. { 5. void* ret = dest; 6. assert(dest && src); 7. while (num--)//后置--,先试用,后--; 8. { 9. *(char*)dest = *(char*)src; 10. dest = (char*)dest + 1; 11. src = (char*)src + 1; 12. } 13. return ret; 14. } 15. int main() 16. { 17. int arr3[] = { 1, 2,3,4,5,6,7, 8, 9, 10 }; 18. int arr4[5] = { 0 }; 19. my_memcpy(arr4, arr3, 20); 20. int i = 0; 21. for (i = 0; i < 5; i++) 22. { 23. printf("%d ", arr4[i]); 24. } 25. return 0; 26. }
知识点:
(1)void* 不能进行加减,所以转换成char *进行加减。
2.7 模拟实现memmove
代码展示:
1. #include <stdio.h> 2. #include <assert.h> 3. void* my_memmove(void* dest, const void* src, size_t num)//能不创建空间就不创建空间 4. { 5. void* ret = dest; 6. assert(dest && src); 7. if (dest < src) 8. { 9. while (num--) 10. { 11. *(char*)dest = *(char*)src; 12. dest = (char*)dest + 1; 13. src = (char*)src + 1; 14. } 15. } 16. else 17. { 18. while (num--) 19. { 20. *((char*)dest + num) = *((char*)src+num); 21. } 22. } 23. return ret; 24. } 25. #include <stdio.h> 26. int main() 27. { 28. int arr3[] = { 1, 2,3,4,5,6,7, 8, 9, 10 }; 29. my_memmove(arr3+1, arr3, 20); 30. int i = 0; 31. for (i = 0; i < 10; i++) 32. { 33. printf("%d ", arr3[i]); 34. } 35. return 0; 36. }