string.h-- 带你模拟实现常见字符串操作 +阅读源码

目录

1.strlen

2.strcpy

3.strcat

4.strcmp

5.strncpy

6.strncat

7.strncmp

8.strstr

9.strtok

 总结


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容器,暂时实现不了......

这个函数的使用也有点特别

下面贴一段例子

 总结

多阅读源码对我们的提升是显而易见的 

在最开始我们写的代码可能比较冗长,性能可能也不如源码  这些都可以通过多阅读源码解决.

模拟实现的代码的思路都不难,因为之前读过源码 所以思路与源码相近!

--------------

如果有启发的话,留个赞再走吧,这对我帮助很大!

不点?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢乙醇的四氯化碳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值