文章目录
strlen的三种模拟实现方式
strlen的参数设计思路:
由于直到长度是不可能为负数,所有返回值设计为 size_t;
由于所求的字符串不可能要修改,所以加const 修饰形参str;
计数器方式模拟实现strlen
size_t my_strlen(const char* str)
{
int count = 0; //统计字符串长度
while(*str != '\0')
{
count++;
str++;
}
//退出循环后,表示到了\0位置
return count;
}
说一说一些设计小细节:
我们这里直接用 str 字符串指针去移动了,为什么不设计一个指针cur直接指向str字符串,让这个cur去移动呢?
很好理解,因为我们函数本来就是要求字符串长度的,并不去要保存str字符串的首地址,所以不需要而外的变量去指向str,直接用str移动更好。
指针-指针的方式实现strlen
size_t my_strlen( const char* str)
{
const char* first = str;
const char* end = str;
while(*end != '\0')
{
end++;
}
//退出循环后 end指向了 \0
return first - endl; //指针 - 指针表示距离
}
递归的方式实现 strlen
递归思想很简单:求大问题化成小问题就行,不要死磕递归的所有过程,因为很容易陷入进去出不来,我们要注重递归的大致方向就行。
比如递归实现strlen,首先明确strlen函数功能求字符串函数长度,那么用递归思想就是求字符串的长度,就可以求出第一个字符串长度+加上接下来第二个起步的剩下的字符串串长度即可。
size_t my_strlen(const char* str)
{
//递归结束条件
if(*str == '\0') return 0;
//来到这里说明*str 不等于\0,那就求字符串长度
return 1 + my_strlen(++str);
}
这个方式求字符串长度的好处就是简单,代码简洁,并且还可以不创建临时变量就可以统计出字符串长度咯
strcat模拟实现
字符串追加模拟实现思路:
找到目标字符串的\0位置,把源字符串拷贝到目标字符串的地方去,直到拷贝完源字符串,同\0也拷贝过去。
char* my_strcat(char* destination,const char* source)//向destination追加source
{
char* temp = destination;//用于保存目的地字符串的首地址,方便返回
while(*destination != '\0')
{
destination++;
}
//来到这里说明destination到了\0的位置
//此时将源字符串source追加
while(*source !='\0')
{
*destination = *source;
destination++;
source++;
}
//来到这里说明source == '\0'
*destination = *source;
return temp;
}
*********************************************************************
*********************************************************************
*********************************************************************
//当然上面的代码还可以精简
char* my_strcat(char* destination,const char* source)//向destination追加source
{
char* temp = destination;//用于保存目的地字符串的首地址,方便返回
while(*destination++){ ; }
//来到这里说明destination到了\0的位置
//此时将源字符串source追加
while(*destination++ = *source++){ ; }
return temp;
}
strcpy模拟实现
思路:源字符串遇到\0就表示拷贝结束了,那么就可以抓这个点去思考。
char* my_strcpy(char* destination,const char* source)//将source拷贝到destination中
{
char* temp = destination; //用于保存目的地字符串的首地址,方便返回
assert(destination && source);//断言一下,空指针直接报错
while( *source != '\0')
{
*dstination = * source;
destination++;
source++;
}
//退出循环后表示 源字符全部拷贝过去
*dstination = * source;
return temp;
}
______________________________________________________________
//有一种比较精简的写法
char* my_strcpy(char* destination,const char* source)//将source拷贝到destination中
{
char* temp = destination; //用于保存目的地字符串的首地址,方便返回
assert(destination && source);//断言一下,空指针直接报错
while(*destination++ = *source++) { ; }
//退出循环后表示 源字符全部拷贝过去
return temp;
}
strcmp模拟实现
字符串比较的实现思路:
抓住对应字符的比较,当不相等时候就直接返回>0或者<0的情况;
和相等的前提下先遇到\0就表示字符串相等且匹配结束,没遇到\0就继续遍历匹配。
int my_strcmp(const char* str1,const char* str2)
{
while(*str1 == *str2)
{
//在相等的前提下,只要有一个字符是 \0,就表示匹配结束,于此同时两个字符串相等返回0
//下面一句代码等价if(*str1) return 0; 或者 if(*str2) return 0;
if(*str1 =='\0'|| *str2 == '\0') return 0;
//相等的前提下,且*str1和*str2字符不等\0,继续前进
str1++;
str2++;
}
//到这里说明来个字符串不等
//返回对应字符相减得到的是十进制的数字,大于0和小于0 的情况都包含了
return *str1 - *str2;
}
strstr模拟实现
strstr查找字符串子串函数,模拟实现的主要思路:
查找到子串,返回的是子串在主串的首地址;
当两个字符串相等时候就一直往前走;前提必须是主串和子串还没到\0;
不相等时候主串就回到原来位置的下一位,子串就回到原来的位置;
char* my_strstr(const char* str1,const char* str2)//在str1查找子串str2
{
const char* pStr1 ;
const char* pStr2;
const char* pre = str1;
while(*pre !='\0')
{
pStr1 = pre; //pStr1指向pre
pStr2 = str2;//pStr2指向str2的首地址
while(*pStr1 == *pStr2 && *pStr1 != '\0' && pStr2 != '\0') //当两字符相等时候
//且还没匹配结束,即主串和子串都还能到\0时候
{
//在*pStr1 == *pStr2前提下,pStr1往前走 pStr2往前走
pStr1++;
pStr2++;
}
//退出循环后,把*pStr2 == '\0'拦截下来,因为表示匹配结束了
if(*pStr2 == '\0') return pre;
//当pStr1 != pStr2时候,pre+1
//为的是,在pStr1 != pStr2时候,pStr1能够找回原来位置的下一个位置
pre++;
}
//退出while(*pre !='\0')表示匹配失败
return NULL;
}
其实这就是一种BF算法,最简单的字符串匹配算法,对应的还有KMP算法呢。但是这里不打算说KMP有兴趣可以去搜一搜。