【strlen函数的使用及strlen函数的三种模拟实现】· C语言详解库函数篇(一)

  • Post author:
  • Post category:其他



大家好,我是Duoni!




开始前言






博主介绍:一位不愿透露姓名的艺术生跨界分子





学习阶段:C语言进阶





信念支撑:业精于勤,只要足够肝,世间就没有跨不了的界!





阅前请求:博主自愧没有任何计算机基础,之所以接触于此,是因为本台电脑频频掉链子,奈何本人骨子里不愿服输的一根筋气质,我励志将自己弄坏的自己修的精神贯彻到底!至此偶然间就接触到了程序,从此便一发不可收拾,日夜沉迷。





我所分享的博文可能没有大佬们优化到极致的最优解,或是妙不可言的神码。但我可以确定的是,我的博文绝对是通俗易懂的,哪怕是小白。我希望在这里记录下我成长的脚印,同时也渴望得到各位大佬们的建议和斧正,就让我们一起前进吧!





介绍完啦!那么我们接下来就……




发车!




目录


开始前言


一、【strlen函数】双连问


(一)、strlen函数是干什么的?


1、strlen函数原型分析


(二)、strlen函数是怎么用的?


二、【strlen函数】的三种模拟实现方式


(一)、计数器法


(二)、递归法


(三)、指针法


三、使用【strlen函数】的易错点及延申


(一)、strlen函数与sizeof操作符的区别


(二)、延申·【sizeof操作符】的使用场景


四、总结







一、【strlen函数】双连问

在学习到数组操作与字符串操作知识点时,大家是否会遇到使用【strlen函数】or【sizeof操作符】求元素个数的苦恼!


在【数组】情况下是该使用【strlen函数】还是【sizeof操作符】呢?在【字符串】情况下又该使用【strlen函数】与【sizeof操作符】中的哪种呢?

当然,之所以会产生这一困扰是有原因的。接下来就跟随我往下一步步刨析吧!


本篇在初始阶段本想向大家分享【strlen函数】的三种模拟实现方式。


但在撰写的过程中,我逐渐发觉【strlen函数】与【sizeof操作符】有着一定的相似点,但又不能作用于同一数据对象。

所以,接下来我会在侧重【strlen函数】知识点分享的同时,也延申一点【sizeof操作符】的知识点。




那么我们开始吧!



(一)、strlen函数是干什么的?

strlen函数是c语言【库】中的一个函数,当然同时也在各种语言中存在着。




【strlen函数】所作的是一个计数器的工作,它从被指定内存的某个位置,逐个向后扫描并计数,直到它碰到’\0’时才会停下,并且返回这一过程中读取到的’\0’以前的一个数位(和),也就是这一段空间中元素的个数。它不在乎该元素的类型大小,它只在乎这一段内存中的元素个数是多少位。


1、strlen函数原型分析

那么到底是什么神仙函数能如此敬业呢?让我们来看看它的函数原型吧:



size_t strlen( const char *



string



)


strlen函数原型解析:


1、strlen函数的返回值是【size_t],这是一个无符号类型的整数(unsigned int)。



(可以这么理解:我们要strlen函数去帮我们数一下目标字符串中元素的数量,它只能兢兢业业的返回这个字符串有几个元素,但是,它绝对不可能返回一个负数。如果它真的返回了一个负数,那我们可以直接说它不靠谱!)


2、它的函数参数为:(const char* string)我们可以怎么理解:由const修饰的指向string(字符串)首元素地址的字符指针。

看到这,真相也大白了:strlen函数所作用的对象是字符串!原因也很直接,因为函数规定:由某个指定位置向后逐个扫描计数,直到遇到’\0’停止并返回计数。

我们回想一下:数组与字符串二者谁是以’\0‘结尾呢?


额……真相只有一个~




只有字符串是以:’\0’结束的!




切记不要与数组搞混了!那么接下来我们来探讨探讨strlen函数是怎么用的吧!


(二)、strlen函数是怎么用的?

strlen函数用起来很省心,你只需要将目标字符串名放入函数调用符中即可。随后,我们需要创建一个整形 变量去接收strlen函数的返回值。

include<stdio.h>

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	count = strlen(vate);
	printf("vate的长度是:%d", count);
	return 0;
}

在这里卖个关子,以下有四个选项,大家认为vate的长度会是多少呢?



A.11                B.14                C.13                D.12

公布答案:



或许有一些新同学会疑惑:我数了里面只有11个字符呀!为什么会是14呢?


(回首往事,我也如此疑惑,后来才知空格也算一个字符!)

好啦!我们已经亲眼瞧见过strlen函数是如何被轻松的使用了。

那么,这时候的我们也该沉重的思考一下:




设计者是怎么设计出这个函数的?





函数的内部是怎么运作的?





我能不能和设计者一样厉害?





思考结束,接下来我们实践出真理吧!



二、【strlen函数】的三种模拟实现方式


(一)、计数器法

首先,第一个方法是:

计数器法

,这个也是最为直观的方法,我最喜欢了!

int my_strlen(const char* vate)
{
	int count = 0;
	while (*vate++ != '\0')
	{
		count++;
	}
	return count;
}

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	count = my_strlen(vate);
	printf("vate的长度是:%d", count);
	return 0;
}

为了能更有趣的吃透理解清这个模拟方法,

我来举个例子吧!




my_strlen函数中,字符串就像一群在桥下游过的小鸭子,而count变量就像一个在桥上数鸭子的小朋友,每经过一只鸭子,小朋友用指头计一个数。但鸭子总会全部游过去,小朋友该怎么停止计数呢?





妈妈告诉他:小军呀!只要在鸭群中没出现小鸡,你就继续数。但如果看见了,你可要赶紧停下来呀!然后把前面的数记在本本上,交给我看。



当然,例子中的“小鸡”指的就是’\0’。




思路阐述:



1、字符串在传参时,传出的是字符串首元素的地址。函数接收后(接收也是字符串的首地址),它可以供函数持续的访问,直到到最后的’\0’处。


例子奉上:

void my_strlen(const char* vate)
{
	printf("%s\n", vate);
}

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	my_strlen(vate);
	return 0;
}


输出结果:




提示:(千万不要对字符串首元素进行修改,不然你会遇上这样的麻烦)



我来试试~

void my_strlen(const char* vate)
{
	vate = 'wo';
	printf("%s\n", vate);
}

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	my_strlen(vate);
	return 0;
}


输出:


很奇怪,为什么会一片空白呢?

其实呢!很有趣:字符串首元素地址的存在,以程序中的vate字符串为例。


在主函数中,vate字符串的空间已经在内存中被开辟,如果按照正常情况:传址——接收——顺序访问,过程应该是很丝滑的。而在 函数中对首元素的修改,让这个字符串指针与后面数据断开了联系,你想让它在修改后再输出原来的数据,这几乎是不可能的。




举个栗子:字符串的首元素就像羊群中的头羊,如果你把这只原头羊换做新的头羊,那么这个羊群就不会跟着你走了。



似乎扯远了,接下来分析剩下的思路:


2、有了第一点后,我们已经可以保证我们可以访问这个字符串的全体了,那么接下来我们就需要进行一个while循环条件的设定:如果没有访问到字符串中的‘\0‘(*vate++ != ‘\0’),就一直得逐个向后访问。


3、最后呢,我们需要安排一个变量,用于每一次进入循环后的++;因为能够进入到循环中,则说明这个元素是非\0的。


(二)、递归法

消化完第一种解法后,接着我们来看看第二种解法。相信【递归】对于大家来说并不陌生,在最初,我也曾迷惑过递归实现的基本原理是什么?

后来,偶然耳畔飘过一句:

出来混迟早要还的!

顿时,我悟了。递归就像一把甩出的回旋镖,不论它飞出了多远,最后都会返回原点方向:一来一回。


即是递归。


可能理解的太过生活化了,但任何基本原理都来源于生活,恒成立!


上代码:

int my_strlen(const char* vate)
{
	assert(vate != NULL);
	if (*vate == '\0')
	{
		return 0;
	}
	else
	{
		return 1 +  my_strlen(vate + 1);
	}
}

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	count = my_strlen(vate);
	printf("vate的长度是:%d", count);
	return 0;
}


输出:




接着我们来细细剖解代码的实现原理:




如果指针vate中的元素不等于’\0’,那么进入到else语句:将指针往后移动一位。再次进入if语句中判断,如果找到’\0\,那么return 0。



是不是理解起来不太友好呢?没事,接下来我们直接上图理解:




千言万语,都汇聚在步骤图中了,小伙伴们理一理呀!递归并不可怕!


关于这个解法,这些小知识需要记住一下!




1、主函数将字符串名传入函数,而字符串名则代表的是字符串的首元素地址,故函数使用指针接收。





2、递归的使用一定要满足两个要点,才算是一个“入门级”的递归。(第一:要设置一个“出口”条件。第二:要让递归无限向出口条件靠近。)



(三)、指针法

终于还是逃不了指针,是的,指针的用处很广,而且很高效。


但它也是一把双刃剑,用的好:指哪打哪!用的不好:指哪偏哪!


指针解法,上代码:

int my_strlen(const char* vate)
{
	assert(vate != NULL);
	char* vate_2 = vate;
	while (*vate_2)
	{
		vate_2++;
	}
	return vate_2 - vate;
}

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	count = my_strlen(vate);
	printf("vate的长度是:%d\n", count);
	return 0;
}


输出:




不得不说:指针这小兄弟能处!


紧接着,我们趁热打铁,来瞧瞧指针解法的实现是怎么实现的:




思路阐述:此处利用到的是:指针的加减运算知识。先将vate首元素赋值给vate_2,让vate_2去找’\0’,意图是让vate_2跑到字符串元素的最末尾,然后与vate中的首元素相减,所得出的就是它们的距离了,即元素个数。





注意点:




一定要觉察到:指针的减法,得出的并不是二者的差(即:13),而是二者之间元素的一个距离(即:14)。



上图理解:

好啦!这就是指针法的解题方法。




提一嘴:指针真的很重要,虽然会有点绕,但一定要静下心来吃透!



三、使用【strlen函数】的易错点及延申


(一)、strlen函数与sizeof操作符的区别

分析完【strlen】函数的三种模拟实现后,我们接着来探讨一下文章开头的问题:




strlen函数与sizeof操作符有什么区别呢?


其实,strlen函数是专门用来计算字符串元素的数量,而sizeof则是用来计算数据类型的大小,两者或许根本搭不上边,但因为C语言语法的自由度高,各位大佬们创造出了以下语句,便让sizeof操作符也可以计算出元素的数量:




sizeof(arr)/sizeof(arr[])


但同样的,以上的写法虽然让sizeof操作符有了计算元素长度的能力,但也仅仅只作用于数组类型。


1、数组名有两种情况下代表整个数组元素:sizeof(数组名)、&数组名。只要sizeof取得整个数组元素后,再除以数组的其中一个元素,就可以计算出数组内的元素数量。


2、如果sizeof用于计算字符串长度时,则会发生麻烦,而这个麻烦的引发者也正是’

\0′.


看代码:

int main()
{
	int count = 0;
	char vate[] = "You can do it!";
	count = sizeof(vate)/sizeof(vate[0]);
	printf("vate的长度是:%d\n", count);
	return 0;
}


结果:




为什么说是’\0’的锅呢?





因为sizeof计算的是元素类型的大小,它不像strlen函数,只计数’\0’之前的数位。sizeof在拿到字符串名后,就开始计算全部元素的大小,它才不做选择,它全要!





最后除以char类型






的大小(1)后,就有了:15这个结果~



(二)、延申·【sizeof操作符】的使用场景


所以,术业有专攻:在遇到字符串与数组类型该如何求长度的问题时。



一定要坚定的知道:字符串用strlen函数求长度,数组类型用sizeof操作符求长度!


四、总结





如果你看到这里了,那么我要跟你说声谢谢!





业精于勤荒于嬉,行成于思毁于随。虽说我非科班出身,但我却无限憧憬成长后的自我,我愿压上我全部的精力去赌一瞬化简成蝶!亲爱的朋友们,我们一起前进吧!





在接下来的时间中,我会以每周两篇的数量进行更新,分享我的知识与感悟,如果喜欢博主,就毫不犹豫的关注我吧!我们一起共进!!













版权声明:本文为Duoni_7原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。