目录:
①不限字符个数型(strlen, strcpy, strcmp, strcat,strstr)
②限字符个数型(strncpy, strcmp, strncat)
③内存型(memcpy, memmove, memset)
通过实现模拟,会更好的了解一些细节!
①限制个数的字符串函数
也就是不需要给个数,只要识别到 '\0' 字符就会停下。
②不限制就是多了个size_t的数字num,只会识别num个(感兴趣的可以自己去模拟哦!)
注意(如果num大于第二个字符串的大小,会自动补充 '\0' )(如果第一个字符串太小了,会越界访问!)
这是strlen函数(字符串长度)的模拟,(size_t)就是无符号整形
形参为指针(起始位置),然后到 '\0'停止计算,最终得到“长度”
size_t my_strlen(const char* str) { unsigned int ret = 0; while (*str++) { ret++; } return ret; }
这是strcpy函数(字符串拷贝)的模拟
形参为目的地指针(起始位置),源头指针(起始位置),最终返回目的地指针的起始位置
char* my_strcpy(char* str1, const char* str2) { char* ret = str1; while (*str1++ = *str2++) { ; } return ret; }
这是strcat函数(字符串延续)的模拟
形参为目的地指针(起始位置),源头指针(起始位置),最终返回目的地指针的起始位置
char* my_strcat(char* str1, const char* str2) { char* ret = str1; while (*str1) { str1++; } while (*str1++ = *str2++) { ; } return ret; }
这是strcmp函数(字符串比较)的模拟
形参为两个字符串的起始位置
(左大于右)返回大于0的数字,反之小于0的数字,相等则为0
int my_strcmp(const char* str1, const char* str2) { while (*str1 == *str2 && *str1 != '\0') { str1++; str2++; } return *str1 - *str2; }
这是strstr函数(字符串查找)的模拟
形参为两个指针,第二个是要查找的,如果在第一个字符串找到一模一样的,那么就返回这个相同字符串的首地址,找不到符号NULL
char* my_strstr(const char* str1, const char* str2) { char* tmp = str2; char* ret = str1; while (*ret != '\0') { str1 = ret; str2 = tmp; while (*str1 == *str2) { str1++; str2++; if (*str2 == '\0') return ret; } ret++; } return NULL; } 这里是实例: int main() { char str[50] = "xXXXasasas"; char s[50] = "XXXX"; char tmp[50] = "xXXXasasas"; printf("%zd \n", my_strlen(str)); printf("%s\n", my_strcpy(str, s)); my_strcpy(str, tmp); printf("%d\n", my_strcmp(str,s)); my_strcpy(str, tmp); printf("%s\n", my_strcat(str, s)); my_strcpy(str, tmp); printf("%p\n", my_strstr(str, s)); printf("%s\n", my_strstr(str, s)); printf("%s\n", my_strstr(str, "XXX")); return 0; }
内存函数:
可以用于一切类型,因为它们的返回类型是void*,接受的也是void*,void*可以包容任何指针,但是使用的时候要强制类型转换!
当然,int*也可以,但是会报警告(指针跳过和指针访问都不一样了),
就是说传参的时候不匹配,有时候没事,有时候有事,
因为不匹配会直接使用定义函数时候的那个类型,这会导致我们不能获得想要的效果,甚至报错,因为设计函数的时候,一些细节被破坏,指针越界之类的....
//memcpy 解决不重叠问题 void* my_memcpy(void* des,const void* sou, size_t num) { void* ret = des; char* pd = (char*)des; char* ps = (char*)sou; while (num--) { *pd++ = *ps++; } return ret; } //memmove 解决重叠问题 void* my_memmove(void* des, void* sou, size_t num) { void* ret = des; char* pd = (char*)des; char* ps = (char*)sou; if (des < sou) { while (num--) { *pd++ = *ps++; } } else { pd = (char*)des + num - 1; ps = (char*)sou + num - 1; while (num--) { *pd-- = *ps--; } } return ret; }
这里有个技巧,就是转化为char*就可以一个一个访问字节
还有,就是遇到重复型,要比较起始位置来确定如何交换
{
① 头到头
②尾到尾
}
最后,memset函数就是把int型数字截断成一个字节,然后按照num一个字节一个字节地“赋值”
//当然也可以是传入一个字符(刚好一个字节)
实例:
#include<string.h> int main() { int i = 0; int arr1[5] = { 1,2,3,4,5 }; int arr2[5] = { 5,6,7,8,9 }; int arr3[5] = { 1,2,3,4,5 }; my_memcpy(arr1, arr2, 12);//返回值为void*,使用时强制类型转化。 for (i = 0; i < 5; i++) { printf("%d ", arr1[i]); } my_memcpy(arr1, arr3, 20); my_memmove(arr1+2, arr1 , 12); for (i = 0; i < 5; i++) { printf("%d ", arr1[i]); } my_memcpy(arr1, arr3, 20); memset(arr1,257, 12); for (i = 0; i < 5; i++) { printf("%d ", arr1[i]); } my_memcpy(arr1, arr3, 20); memset(arr1, 1, 12); for (i = 0; i < 5; i++) { printf("%d ", arr1[i]); } return 0; }