strlen函数的模拟实现

strlen函数的模拟实现

目录

  1. 主要的知识点:
    (1)指针传参的本质
    (2)strlen函数的特性
    (3)代码设计的基本思路
  2. 一些穿插的关于scanf的知识点

正文

1.(1)(2)(3):
对于strlen,首先它的作用就是计算字符串的长度,相信大家都知道strlen函数的原理是:直到读取到\0才停下来(注意:这里的读取到\0所计算出来的长度是不包含\0的,也即字符串的表面长度)。其次它的返回值是size_t即无符号整形,所以要想使我们的代码更加准确可以把int替换为size_t。接下来就是strlen的传参了,它的传参其实是传入了字符串首元素的地址,我们类比一下我们也能的出指针传参的本质其实也就是传入首元素的地址,所以我们模拟时可以用指针来传参。至于基本思路也就是main函数基本框架再加设计一个函数来计算字符串的长度,当然头文件也必不可少。
其实写代码的步奏也体现了一个代码的写作思路,下面我将用及为详细的步奏来体现我的写作思路:

#include <stdio.h>
int main()
{

return 0;
}

这是我们一般写代码的主体框架,但要想计算一个字符串的长度肯定是少不了字符串啊,所以我们可以先创建一个字符数组。

#include <stdio.h>
int main()
{
char arr[]="abcdef"

return 0;
}

接下来就是创建函数了,由于模拟的英文是imitate,为了方便我们就把创建的函数名暂定为im_strlen

#include <stdio.h>
int main()
{
char arr[]="abcdef"
im_strlen();
return 0;
}

下面就是该函数的参数和返回值了,我们想计算字符串的长度,而长度为整形,所以该函数的返回类型就是整形int,进而我们可以用ret来接收该函数的返回值;至于参数,我们可以回想strlen的参数,它是数组名(也能看作数组首元素的地址)因此我们可以将数组首元素的地址传入,再用一个char类型的指针接收

int im_strlen(char *p)
{

}
#include <stdio.h>
int main()
{
char arr[]="abcdef"
int ret =im_strlen(arr);
return 0;
}

接下来就是函数的内部设计了,首先要提一嘴:因为我们传入的是该数组首元素的地址,所以我们可以用指针加整数的方式来求,而指针加上一个整数表示跳过一个该类型的元素(说明白点就是跳过一个元素),所以我们可以用:指针+0访问第一个元素;用指针+1访问第二个元素……指针+i 访问第i-1个元素。讲到这就引发了一个问题我们好像不知到我们到底该访问几个元素,所以这时我们可以用sizeof来计算该字符数组的元素个数,该个数可以存在sz里(这里其实如果要用sizeof我们是直接可以得出整个元素个数的,但为什么还要再设计一个函数去算呢?这里出现了矛盾,所以这种思路是不正确的,第一种解决办法是不设计函数直接用sizeof来算,但这种方法要注意sizeof的计算是包含\0的所以要将算得的结果-1,并且这种方法只适用于字符串,因为只有字符串才默认在它的末尾带了个\0;第二种解决办法是从思路错误处来改正。上面我们说我们不知道到底该访问几个元素,所以才想到去用sizeof来计算总的元素个数,但如果我们再仔细的想想:难道我们真的必须要知道总元素的个数吗?答案是:“不一定”,另一种思路是利用字符串的特性,即:每个字符串的末尾必然会有\0,所以我们可以做一个判断:如果读取不到\0就一直加加,这样是不是就能算出所有的元素个数了,现在我们还缺一个计数器我们就先把它命名为count吧)从第二个思路出发我们就能写代码了(在这里我们着重介绍地二种法,第一种我们是可以自行实践的);

int im_strlen(char *p)
{
	int count=0;
	if(*p!='\0')
	{
	p++;
	count++;
	}
	return count;
}
#include <stdio.h>
int main()
{
char arr[]="abcdef"
int ret =im_strlen(arr);
return 0;
}

这样设计程序其实就已经成了,但当我们运行起来时,我们会发现结果不尽人意,
一是:好像频幕上并无东西打印出来
二是:就算打印出来了也达不到我们想要的结果
解决方案如下,我们之所以没有打印出来结果是因为我们压根没有调用prinrf打印函数,而即使加上了打印函数我们的结果也是1,一定不是6,我们这是因为忽略了该程序其实只执行了一次,所以我们可以把if改为while循环,这样就行了。

int im_strlen(char *p)
{
	int count=0;
	while(*p!='\0')
	{
	p++;
	count++;
	}
	return count;
}
#include <stdio.h>
int main()
{
char arr[]="abcdef";
int ret =im_strlen(arr);
printf("%d\n",ret);
return 0;
}

该代码的优化,
虽然上述代码可以运行,但这样的代码仍然有缺陷,
一是:我们真正的strlen的返回值是size_t无符号整型,而我们用的却是int,虽然也能用,但考虑到真正的字符串的长度肯定不可能为负,所以用size_t会更合适
二是:在我们传入指针参数时,我们难道传入的一定是可用指针吗?万一我们传入了空指针怎么办?所以这里就要用到assert断言用来判断,该断言的使用比较简单:就是当满足条件时该断言不会产生任何影响,但如果不满足就会产生程序错误,迫使程序员查漏,该断言对程序员是很友好的虽然它在debug版本下会使程序运行的时间变长,但在用户方面是没有任何影响的,当然使用assert当然少不了它的头文件了,
三是:当我们在运行我们写的函数时是不希望我们的字符串在执行过程中被更改的,所以,我们可以在*p前加const来限制字符串的元素不能被更改。
所以,优化后的代码就是:

#include<assert.h>
size_t im_strlen(const char *p)
{
	int count=0;
	assert(p!=NULL);
	while(*p!='\0')
	{
	p++;
	count++;
	}
	return count;
}
#include <stdio.h>
int main()
{
char arr[]="abcdef";
size_t ret =im_strlen(arr);
printf("%d\n",ret);
return 0;
}

最后要注意:
assert的头文件应该写在代码首,反正写在#include<stdio.h>旁边不行,由于main函数是程序的入口,难道不应该从main以上来读取吗?但为什么只有写在最开头才能运行呢?具体我也不知道。
由于打印的数据类型是size_t所以我们可以使用%zd来打印,会更准确。
2.关于scanf的误区
因为scanf在读取数据时不是过滤掉一切空格吗(%c除外),我曾经认为(%d )中的%d后的空格也会过滤掉但并不是那样,事实是:理论上说的过滤不是过滤掉这里的括号里的空格,而是我们输入界面时的空格;这里的空格是在我们输入时要在数据后加的,如果不加够的话,即使你按enter它也不会执行;
总结:按()内的格式来输入,同时printf输出时也是按照我们的既定格式来输出;
补充:scanf的返回值为:成功读取的元素个数,假如你在输入时按了3次ctrl+z则会提前结束输入(也可能按的次数各有不同),这里的按三次ctrl+z是:“按一次ctrl+z后紧接着加一次回车”,如此反复才能提前结束输入。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值