目录
1.strlen
计数器、指针、递归是比较常见的写法
下面是指针和递归的写法
(别问为啥不写计数器,问就是懒
//指针
size_t my_strlen(char* res)
{
assert(res);
char* tmp=res;
while (*tmp)
{
tmp++;
}
return tmp - res;
}
//递归
size_t my_strlen2(char* res)
{
assert(res);
if (!*res)
{
return 0;
}
return 1 + my_strlen2(++res);
}
再来看看源码:
源码采用的是指针的写法 清晰易懂 不懂就自己举个例子模拟一下
注:跳出while循环时 eos指向的是'\0'后面一个位置 所以返回值要减1.
解释:eos指向'\0'时结束循环 但还有后置++,所以eos再往后移一位
2.strcpy
实现办法太多了,思想都是一个一个拷贝,下面是简洁的写法 贴近源码
char* my_strcpy(char* des, const char*src)
{
assert(des&&src);
char* ret=des;
while (*des++ = *src++);
return ret;
}
3.strcat
字符串的追加
找到'\0' -> 从'\0'开始模仿strcpy的操作即可(从'\0'开始包括了'\0')
char* my_strcat(char* des, const char* src)
{
assert(des&&src);
char* ret = des;
while (*des++);
--des;
while (*des++ = *src++);
return ret;
}
源码的写法 清晰易懂
4.strcmp
int my_strcmp(const char*s1,const char* s2)
{
assert(s1&&s2);
while (*s1&&*s2&&*s1 == *s2)
{
++s1;
++s2;
}
if (!*s1&&!*s2) return 0;
if (*s1 > *s2) return 1;
return -1;
}
源码
亮点:借用ret unsigned char*的使用
思考:源码比较 字符串 abc和abcdef的过程
源码比较 字符串 abcdef和abc的比较
5.strncpy
加一个参数罢了,模拟实现类似strcpy
char* my_strncpy(char* des, const char*src,long long count)
{
assert(des&&src);
char* ret = des;
while (count-- && (*des++ = *src++));
if (count==-1) *des = '\0';
return ret;
}
源码
注:源码把多余出来的位数全改成'\0';而我模拟实现时只改了一个
例: s1="abcd" 拷贝s1放进s中 n取500
此时my_strncpy后面只有1个'\0' 而源码后面还会拷贝465个'\0'
最后一共会有466个'\0' (因为*dest++=*src++也会拷贝一个'\0'然后跳出循环)
6.strncat
思路同理
贴上源码以供参考
7.strncmp
由源码得到的思路:把步长确定为4,每次处理4个字符,类似指针的移动
当然不是所有的数都能整除4
比如比较6个字符 此时6%4==2,再单独处理最后两个字符即可
你会发现
if (*(first-4) == 0 || *(first-4) != *(last-4))
if (*(first-3) == 0 || *(first-3) != *(last-3))
if (*(first-2) == 0 || *(first-2) != *(last-2))
if (*(first-1) == 0 || *(first-1) != *(last-1))
这几行代码的本质是一样的
*(first-4)看是不是末尾 是的话直接返回
或者
*(first-4) != *(last-4))看两个字符是不是相等 不相等直接返回
//仔细对比strcmp和strncmp会发现思路其实差不多
如果还是很模糊 可以自己代入两个字符串走一下这个函数 思路就会清晰起来
这个办法比一个一个遍历更快一点 更像一个筛子 这种思想值得借鉴
8.strstr
先思考:
abcdef 中找 de
再思考
abbbbccdd 中找 bbc
第一个匹配到的位置即找到的字符串的起始位置 也就是要返回的位置
从匹配的角度:
第一个例子里直接遍历即可,不需要记录第一个匹配到的位置(即字符‘d’)
而
第二个例子里则需要一个指针记录下第一个匹配到的位置(即字符‘b’)
从返回值的角度:
不管哪个例子都需要一个指针来记录一下返回值的位置
综上,需要一个指针来记录一个返回值(下文代码中的tmp就是这个作用)
char* my_strstr(const char* str1, const char* str2)
{
assert(str1&&str2);
if (*str2=='\0')
{
return (char*)str1;
}
const char* s1 = NULL;
const char* s2 = NULL;
char* tmp = (char*)str1;
while (*tmp)
{
s1 = tmp;
s2 = str2;
while (*s2&&*s1&&(*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return tmp;
}
++tmp;
}
return NULL;
}
//字符0 的ASCII值是48 不是0 所以当*s2=='0'时*s2为真
//只有'/0'的ASCII值是0 所以可以把*s2!='\0'简化为*s2
源码
9.strtok
模拟用到了map容器,暂时实现不了......
这个函数的使用也有点特别
下面贴一段例子
总结
多阅读源码对我们的提升是显而易见的
在最开始我们写的代码可能比较冗长,性能可能也不如源码 这些都可以通过多阅读源码解决.
模拟实现的代码的思路都不难,因为之前读过源码 所以思路与源码相近!
--------------
如果有启发的话,留个赞再走吧,这对我帮助很大!
不点?