字符串函数剖析(1)

news2025/2/4 13:02:56

带你玩转字符串

1.strlen函数不一样的细节

1.1模拟实现strlen函数

2.strcpy函数的巧妙

2.2strcpy的模拟实现

3.strcmp函数的巧妙

3.2strcmp的模拟实现

详解strlen的细节

首先了解strlen 函数的参数

size_t strlen ( const char * str );

size_t 是什么东西呢?
看下面的操作:
在这里插入图片描述
这里介绍一个快捷键,输入size_t后,按住ctrl + 鼠标左键,即可转到定义,或者右击鼠标,点击转到定义即可
所以 size_t == unsigned int ,strlen 的返回类型是无符号类型

注意这里,这是无符号整型!下面的介绍大有用处

下面介绍strlen 的用法:
strlen是一个库函数,它会顺着你 传过来的地址,一直往下找,直到找到\0为止,返回的是无符号整型

在这里插入图片描述

输出结果为6

再看下面的代码:
在这里插入图片描述
结果还是6吗,不再是6了,而是一个随机值。字符串这样放在数组里,没有\0,所以strlen会顺着arr不断往下找,什么时候找到\0,我们不得而知。

这证实strlen是顺着地址往下找的。

模拟实现strlen

int my_strlen(const char* str)
{			//const修饰的内容无法更改
	int count = 0;
	assert(str != NULL);
	while (*str) 
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	int len = my_strlen("abcdef");
	printf("%d\n", len);
	return 0;
}

打印出来的结果仍然是6,这里要讲的重点不是如何实现strlen函数。
细心的你会发现:
strlen 函数的返回值不应该是size_t 吗,为什么上面写的是 my_strlen 是 int 类型呢?

是因为: 其实这两种写法都可以,各有利弊:
先看下面的一段代码:

int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
		注意这里是库函数的strlen
	{
		printf("hehe\n");
	}
	else
	{
		printf("haha\n");
	}
	return 0;
}

请说出上面代码的输出结果:
没注意到细节,一定会说出会打印haha,运行出真知:
在这里插入图片描述
为什么呢?
回到上面的strlen的返回类型,size_t,是 unsigned int ,无符号整型,abc的长度是3,abcdef长度是6,那么3-6 == -3 ,-3作为 unsigned int 类型,是一个大于0的数,
打印结果如下图:
在这里插入图片描述
是一个大于0的数,所以会打印hehe,
假如是用自己的my_strlen 函数,结果如下:

在这里插入图片描述
这就很符合我们的认知, 3 - 6 == -3 <0,走else 语句。
不过,这两种写法,各有各的好处,假如你想跟着标准走的话,写size_t是绝对没有问题的,因为计算长度是不可能有负数的。
但是写 int 类型,也没有什么问题,单独计算一个字符串的长度时,返回值也是一个大于0的数,当3 - 6 == -3时,的确是会走if 语句,更符合我们的理解,不容易产生歧义。
所以两种写法各有利弊。
注意事项:
在这里插入图片描述

2.strcpy函数的巧妙讲解

先看库函数的声明:

char * strcpy ( char * destination, const char * source );
						目的地					源头

需要两个地址,一个是目的地地址,一个是源头地址

举个例子:

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "hello";
	strcpy(arr1, arr2);
	     将arr2字符串拷贝到arr1
	printf("%s\n", arr1);
	
}

运行结果如下:

在这里插入图片描述

下面来模拟实现:

模拟实现strcpy函数:

char* my_strcpy(char* dest,  char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*src!='\0')
	{
		*dest = *src;
		 dest++;
		 src++;
	}
	*dest = *src;
	//循环结束后,src指向了\0的位置,所以将\0也赋值给dest;
	return ret;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "hello";
	char *ret = my_strcpy(arr1, arr2);
	printf("%s\n", ret);
}

特殊位置已注释讲解 ,但是你会发现,模拟代码还可以精简化

char* my_strcpy(char* dest, const char* src)
				目标空间必须可变,源头空间不可变
{
	assert(dest && src); 判断指针的有效性
	char* ret = dest;
	while (*dest++ = *src++);
	return ret ;
}

每次src对应的字符赋值给dest后,再++,dest也++,然后进行判断,如果为\0 , \0的ascii码值为0,while为0,退出循环

这样的代码才是,满分代码

strcpy注意事项:
在这里插入图片描述

	char arr1[] = { 'a','b','c','d','e','f' };
	错误代码:字符串无\0
	char arr1 = "abcdef";
	错误代码:常量字符串无法更改

在这里插入图片描述
请注意第三点:目标空间必须足够大。
这是因为strcpy这个函数,它只管拷贝,只管找到\0才停止,它才不管你的空间够不够,这就是strcpy函数的脾气,所以必须充分了解。

strcmp函数详解

首先了解函数的声明:

int strcmp ( const char * str1, const char * str2 );

strcmp的参数是两个不可更改的char*的指针

返回值:当第一个字符串大于第二个时,返回一个大于0的数,当第一个字符串小于第二个时,返回小于0的数,等于时,返回0

在这里插入图片描述
测试一下结果:
在这里插入图片描述
但是这里,在visual studio环境下,返回值只是-1,0,1,是不是说这个strcmp函数有问题呢?其实并不是,当我们模拟实现的时候就能够发现。
下面来模拟实现strcmp函数:

模拟实现strcmp

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
		{
			return 0;//相等的情况
		}
		str1++;
		str2++;
	}
	return (*str1 - *str2);//不相等的情况
}

int main()
{
	char* p1 = "abcdef";
	char* p2 = "sqwer";
	int ret = my_strcmp(p1,p2);
	printf("%d", ret);
	return 0;
}

可以看到,a和s相比,相差了18,a的ascii码值是97,s的ascii码值是115,两者相减,结果就是-18,所以p1 小于 p2
在这里插入图片描述

strcat函数剖析

这是一个追加函数,意思是在原字符串的末尾,继续追加其他字符串。

char * strcat ( char * destination, const char * source );

该函数的声明如上:
参数是两个指针,一个是目的地指针,一个是源头指针。
返回类型是目的地起始地址。

int main()
{
	char arr1[30] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);

来看一下strcat函数的实现过程,在这里插入图片描述

在arr1之后追加了arr2.
但是会不会连world末尾的\0也追加上去呢?
答案是会的:
在这里插入图片描述
可知,world后面连\0也追加上去了;

那么能不能自己追加自己?

可以看到,程序崩溃了
在这里插入图片描述

原因究竟是什么?
在这里插入图片描述
调试之后我们发现,arr1没有\0了!,hello未被追加时,后面还有一个\0,但是追加之后,arr2是从\0开始追加的,所以当我们追加之后,\0已经被覆盖了。所以它会无限追加下去。所以这个程序就崩溃了。

模拟实现strcat函数:

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	//1.找到目的字符串的\0位置
	while (*dest!='\0')
	{
		dest++;
	}
	//2.追加的过程其实就是拷贝的过程
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[30] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
}

重点部分已经作了注释:

不过有几点要注意一下:

在这里插入图片描述

与strlen相似,如果源字符串后无\0,这就像自己追加自己,导致程序崩溃
如下图:
在这里插入图片描述
arr1的只有6个大小的空间,如果强制追加arr2上去,就会导致程序崩溃。
当源头字符串后面没有\0时,会出现:
在这里插入图片描述
追加过去之后,但是后面没有\0,就没有\0追加,无结束标志,程序会崩溃。

如果对你有帮助的话,就关注一下吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

链表-------数据结构

链表(重点): 链表是物理存储结构上面非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序实现的 1)在顺序表中&#xff0c;我们不光引入了一段连续的内存&#xff0c;还引入了一块连续的内存空间&#xff0c;叫做usedsize&#xff0c;来表示对应数组中…

PMP每年考几次,费用如何?

PMP每年考四次&#xff0c;整个考证一次通关大致需要 7000 元左右&#xff0c;主要是下面几项费用&#xff1a; 部分学习笔记&#xff1a; 一、考证费用 分为基础费用报班费用 基础费用&#xff1a;报名费续证费用&#xff08;补考费 / 退考费&#xff09; 报名费 3900 元是固…

【软件测试】测试人的内卷,掀起血雨腥风......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 铺天盖地的职场内卷…

如何利用深度学习中的AutoEncoder进行特征降维和特征可视化,pytorch代码

我们将使用 Pytorch 中的 AutoEncoder(自动编码器架构)来减少特征维度和可视化。 北大出版社&#xff0c;人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理 人工智能原理与实践 全面涵盖人工智能和数据科学各个重要体系经典 首先&#xff0c…

力扣(142.1002)补9.17

142.环形链表Ⅱ 不会&#xff0c;不过答案用了数学的想法&#xff0c;我以为计算机里只有暴力呢。 public class Solution { public ListNode detectCycle(ListNode head) { if(headnull||head.nextnull) return null; ListNode phead; ListNode p2head; while(true){ if(p2.ne…

Excel教程之学生成功所需的 5 个电子表格

作为一名学生,跟踪你盘子里的所有任务和责任可能会让人不知所措。 这就是为什么拥有一套组织良好的电子表格可以成为救命稻草的原因。出于多种原因,维护自己的电子表格可能是一项宝贵的技能。首先,它可以帮助您养成良好的习惯,例如组织和关注细节。通过创建和维护您自己的…

RabbitMQ之Exchange(交换机)

目录 一、Exchange简介 二、Exchange(交换机)的类型 1.直连交换机&#xff1a;Direct Exchange 2.主题交换机&#xff1a;Topic Exchange 3.扇形交换机&#xff1a;Fanout Exchange 4、默认交换机 5、Dead Letter Exchange&#xff08;死信交换机&#xff09; 三、交换机…

Conan 上传预编译的包

目录 1. 组织文件 2. 编写conanfile.py 3. 然后执行export 命令 4. 上传到自己的center 疫情肆虐&#xff0c;阳了一周&#xff0c;今天可以正常工作了&#xff0c;刚接触conan, 确实一脸懵逼&#xff0c;今天的任务是把项目转成Conan 管理&#xff0c;因为项目用到了第三方…

R语言学习笔记——扩展篇:第十九章-使用ggplot2进行高级绘图

R语言 R语言学习笔记——扩展篇&#xff1a;第十九章-使用ggplot2进行高级绘图 文章目录R语言一、R中的四种图形系统二、ggplot2包介绍三、用几何函数指定图的类型四、分组&#xff08;重叠图形&#xff09;五、刻面&#xff08;并排图形&#xff09;六、添加光滑曲线七、修改…

SpringMVC的AOP总结

SpringMVC的AOP总结 1、Filter 过滤器 Filter是Servlet规范中规定的&#xff0c;只能用于WEB中, 在Servlet前后起作用 它可以对几乎所有请求进行过滤&#xff0c;但是缺点是一个过滤器实例只能在容器初始化时调用一次 使用场景: 修改字符编码; 对入参进行校验, 校验不通过返回…

java实验报告之Employee类的设计

一个不知名大学生&#xff0c;江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2022.12.20 Last edited: 2022.12.20 目录 一、实验目的 二、实验内容 三、总体设计&#xff08;设计原理、设计方案及流程等&#xff09; 四…

Python数据结构+算法全面讲解:定义函数、定义类

之前的过程抽象例子调用了 Python数学模块中的 sqrt 函数来计算平方根。通常来说,可以 通过定义函数来隐藏任何计算的细节。函数的定义需要一个函数名、一系列参数以及一个函数体。 函数也可以显式地返回一个值。例如,下面定义的简单函数会返回传入值的平方。 >>> …

使用 Appium 报错“... Could not find ‘adb‘ in ...”

使用 Appium 报错 “... Could not find adb in ...”1. 现象2. 问题定位3. 解决方案4. 验证1. 现象 在 Robot Framework 中使用 Open Application 关键字以通过 Appium 来打开模拟器上的应用报错&#xff1a; WebDriverException: Message: An unknown server-side error occ…

Transformer17

还是transformer 这次还是谷歌哈 又在机器人领域发力 谷歌机器人团队等在机器人领域构建了一个多任务 transformer 模型&#xff0c;显著改进了对新任务、环境和对象的零样本泛化。轻松完成700多条指令、成功率达97%&#xff01;谷歌开源机器人领域 我们知道&#xff0c;机器…

Docker搭建MySQL主从集群

使用Docker搭建一主一从的MySQL集群&#xff0c;使用的是8版本的MySQL镜像不是8的版本部分命令会无效&#xff0c;宿主机任意 规划 端口角色3307master3308slave 思路 事先准备 要确保linux宿主机已经安装上Docker。然后将MySQL镜像下载到本地 &#xff0c;可以先去Docker Hu…

ssm java mysql_医院门诊管理系统_

息化不断建设发展的今天&#xff0c;医院看病预约&#xff0c;医生的挂号等&#xff0c;已经十分方便&#xff0c;通过在线挂号&#xff0c;医生的查看&#xff0c;就能够了解到医院的门诊基本信息&#xff0c;并且可以在线进行门诊的医生查看&#xff0c;医院最新的资讯等&…

Golang 【basic_leaming】切片

阅读目录1、为什么要使用切片2、切片的定义3、关于nil 的认识4、切片的循环遍历5、基于数组定义切片6、切片再切片7、关于切片的长度和容量8、切片的本质9、使用 make() 函数构造切片10、切片不能直接比较11、切片是引用数据类型 -- 注意切片的赋值拷贝12、append() 方法为切片…

Mycat(10):分片详解之固定分片hash算法

1 找到conf/schema.xml并备份 2 固定分片hash算法 本条规则类似于十进制的求模运算&#xff0c;区别在于是二进制的操作,是取id的二进制低10位&#xff0c;即id二进制 。 此算法的优点在于如果按照 10进制取模运算&#xff0c;在连续插入1-10 时候1-10会被分到1-10个分片&…

手机号格式检查系统(Java)

本系统支持的手机号检查如下所示&#xff1a; /** * 中国移动&#xff0c;中国联通&#xff0c;中国电信都为11位的手机号 * 中国"移动"前三位: * 135、136、137、138、139、147、150、151、152、157、 * 158、159、172、178、182、183、184、187、188、195、197、19…

铝网初效过滤器及金属网过滤器的区别

广州特耐苏净化设备有限公司详细介绍&#xff1a;粗效过滤器主要技术参数 什么叫铝网初效过滤器及金属网过滤器?铝网初效过滤器也叫金属网过滤器也可叫GH金属孔网过滤器只是人们的叫法不同。 铝网初效过滤器均具安全&#xff0c;坚固&#xff0c;耐高温,耐酸碱,之特性.一般应…