【C语言】字符函数和字符串函数(1)

news2024/11/16 11:59:21

#国庆发生的那些事儿#

大家好,我是苏貝,本篇博客带大家了解字符函数和字符串函数,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 1.本章重点
  • 2. strlen
    • 2.1函数介绍
    • 2.2 模拟实现
  • 3. strcpy
    • 3.1 函数介绍
    • 3.2 模拟实现
  • 4.strcat
    • 4.1 函数介绍
    • 4.2 模拟实现
  • 5. strcmp
    • 5.1 函数介绍
    • 5.2 模拟实现
  • 6.strncpy
    • 6.1 函数介绍
    • 6.2 模拟实现
  • 7.strncat
    • 7.1 函数介绍
    • 7.2 模拟实现
  • 8.strncmp
    • 8.1 函数介绍
    • 8.2 模拟实现
  • 9.strstr
    • 9.1 函数介绍
    • 9.2 模拟实现

1.本章重点

  • 求字符串长度
    strlen
  • 长度不受限制的字符串函数
    strcpy
    strcat
    strcmp
  • 长度受限制的字符串函数介绍
    strncpy
    strncat
    strncmp
  • 字符串查找
    strstr
    strtok
  • 错误信息报告
    strerror

以上函数的头文件都为<string.h>


2. strlen

2.1函数介绍

size_t strlen ( const char * str );

注意:
1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
2.参数指向的字符串必须要以 ‘\0’ 结束,否则函数返回值为随机值
3.注意函数的返回值为size_t,是无符号的( 易错 )
点击该链接继续了解strlen

问:下面代码输出的结果是什么?

int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "bbb";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2>str1\n");
	}
	else
	{
		printf("srt1>str2\n");
	}
	return 0;
}

答案:str2>str1
这和你想的是否一样?其实这蕴含的知识点在注意的第三条,函数的返回值为size_t,是无符号的,所以strlen(str2) 和 strlen(str1)的返回值都是无符号的,无符号数-无符号数=无符号数>=0,又strlen(str2) =3不等于 strlen(str1)=6,所以结果>0,因此输出的是str2>str1

2.2 模拟实现

strlen的模拟实现在之前就有写过,如果感兴趣的话,可点击下方链接直接跳转
自定义实现strlen函数的3种方法


3. strcpy

3.1 函数介绍

char* strcpy(char * destination, const char * source )

strcpy函数的作业是拷贝字符串,即将源字符串拷贝到目标空间中,拷贝时会将源字符串中的 ‘\0’ 一起拷贝。所以目标空间必须可以改变,且其大小>=源字符串(包括’\0’)。函数的参数有2个,第一个是目标空间的起始地址,第二个是源字符串的起始地址,类型都为char *,又因为strcpy函数不会改变源字符串的内容,所以char * source左边用const修饰。函数的返回值是目标空间的起始地址,所以为char *

示例1:
源字符串必须要有’\0’,否则会一直访问arr2后面的元素直至找到’\0’,可能会越界,造成程序运行异常,如下:

int main()
{
	char arr1[20] = "xxxxxxxxxx";
	char arr2[] = { 'a','b','c' };
	strcpy(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

示例2:
目标空间必须可变,否则会造成程序运行异常,"abcdefg"是常量字符串,不可更改,p存储的是字符串的首元素地址即a的地址

int main()
{
	char* p = "abcdefg";
	char arr2[] = "hello";
	strcpy(p, arr2);
	printf("%s", p);
	return 0;
}

在这里插入图片描述

示例3:
会将源字符串中的 ‘\0’ 拷贝到目标空间。

int main()
{
	char arr1[20] = "xxxxxxxxx";
	char arr2[] = "hello";
	strcpy(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

总结:
1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

3.2 模拟实现

my_strcpy函数参数依旧是2个,返回值仍然是目标空间的初识地址,所以char* my_strcpy(char * str1, const char * str2 )。下面开始拷贝,用while循环,当 * str2为’\0’时退出循环,否则将str2指针指向的值赋给str1指向的值,str1++,str2++。当退出循环时,* str2指向的是’\0’,再将’\0’赋给 * str1。

char* my_strcpy(char* str1, const char* str2)
{
	char* ret = str1;
	while (*str2)
	{
		*str1 = *str2;
		str1++;
		str2++;
	}
	*str1 = '\0';
	return ret;
}

我们发现,上面代码完全可以简化成下述代码:while循环中,str1和str2的自增都是后置++,即先使用再自增,将str2指针指向的值赋给str1指向的值,再自增。等到 * str2==‘\0’时,也会将’\0’赋值给*str1,两指针再自增,退出循环

char* my_strcpy(char* str1, const char* str2)
{
	char* ret = str1;
	//断言,如果str1或str2中有空指针,会在运行时报错并会显示错误在第几行
	//头文件为<assert.h>
	assert(str1 && str2);
	while (*str1++ = *str2++)
		;
	return ret;
}

int main()
{
	char arr1[20] = "xxxxxxxxxx";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

4.strcat

4.1 函数介绍

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

追加函数,即将源字符串追加到目标字符串后。比如目标字符串为“hello”,源字符串为“world”,使用strcat函数后,目标字符串变为“helloworld”。函数有2个参数,第一个是目标字符串的起始地址,第二个是源字符串的起始地址,类型都为char *,又因为strcat函数不会改变源字符串的内容,所以char * source左边用const修饰。函数的返回值是目标空间的起始地址,所以为char *。源字符串的第一个字符将会覆盖目标字符串末尾的’\0’。

和strcpy函数相似,因为都需要访问源字符串,所以源字符串必须以’\0’结束,以免越界。目标空间也必须足够大,能容纳下源字符串的内容。目标空间必须可修改。

示例1:

int main()
{
	char arr1[20] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

示例2:
自己追加自己,虽然这可行,但最好还是不要这样写

int main()
{
	char arr1[20] = "hhh";
	strcat(arr1, arr1);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

总结:
1.源字符串必须以 ‘\0’ 结束,在拷贝时将’\0’也拷贝过去
2.目标空间必须足够大,能容纳下源字符串的内容。
3.目标空间必须可修改。
4.目标空间中必须有’\0’,保证能找到目标空间的末尾
5.字符串可以自己追加自己

4.2 模拟实现

在模拟实现之前,我们想到strcat函数是先找到目标空间的末尾即’\0’位置处,再将源字符串的字符逐个追加到目标空间中,包括源字符串的’\0’,追加的第一个字符会覆盖目标空间原本的’\0’。所以我们模拟实现的思路与它一致,先找到目标空间的末尾,只需用while循环,当 * str1=='\0’时退出循环,就找到了目标空间的末尾。第二步,追加,与strcpy相似,上面有详细介绍,这里就不再赘述了

char* my_strcat(char* str1, const char* str2)
{
	char* ret = str1;
	assert(str1 && str2);
	//1.找到目标空间的'\0'
	while (*str1)
		str1++;
	//2.追加
	while (*str1++ = *str2++)
		;
	return ret;
}

int main()
{
	char arr1[20] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

写完上面代码后,我们不禁想起来strcat函数还能自己追加自己,那我们写的这串代码可以吗?答案是不可以。刚开始时,str1和str2都指向首元素h
在这里插入图片描述
在找到目标空间的’\0’后,str1指向’\0’
在这里插入图片描述
开始追加,将 * str2赋值给 * str1,所以str1指向的内容变为h
在这里插入图片描述
继续追加,当str2指向下图所在位置时,该位置的元素已经从’\0’变为h,再将h赋值给 * str1,所以整个过程中 * str1都不会被赋值为’\0’,所以会一直循环下去,程序会崩溃
在这里插入图片描述


5. strcmp

5.1 函数介绍

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

strcmp是string compare的缩写,即字符串比较,不过不是比较长度,而是比较对应位置上字符的大小(ASCII码值)。strcmp函数的参数是两字符串的首元素地址。若 * str1> * str2,返回一个正数;若相等,返回0;若 * str1< * str2,返回一个负数。比如用strcmp函数比较字符串“abcdefg”和“abqa”,第一二个位置上字符的大小相等,比较第3个字符的大小,ASCII码值中c<q,返回一个负数,不用再比较“fefg”和“a”的大小。因为不会改变arr1和arr2的内容,所以用const修饰char * str1.2

int main()
{
	char arr1[] = "abc";
	char arr2[] = "abaa";
	char arr3[] = "abc";
	char arr4[] = "abq";

	int ret1 = strcmp(arr1, arr2);
	int ret2 = strcmp(arr1, arr3);
	int ret3 = strcmp(arr1, arr4);

	printf("%d %d %d", ret1, ret2, ret3);
	return 0;
}

在这里插入图片描述

5.2 模拟实现

strcmp函数的原理很简单,就是从两个字符串第一位开始比,若相同则比下一位,不同就返回值。来模拟实现,当 * str1和 * str2相等时,用while循环,相等则str1和str2都自增。如果进入循环时有一个的值为’\0’,那么另一个的值也为’\0’,说明两个字符串完全相等,返回0;若因为两个值不同退出循环,比较两值大小

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}

上面代码也可简化为:两值相减,若左>右,则返回正数;反正返回一个负数

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;
}

6.strncpy

上面我们了解了strcpy,strcat,strcmp三个函数,它们是长度不受限制的字符串函数。下面我们再来了解一下长度受限制的3个字符串函数strncpy,strncat,strncmp

6.1 函数介绍

char * strncpy ( char * destination, const char * source, size_t num );
strncpy和strcpy函数及其相似,只不过前者多了一个参数size_t num,表示只从源字符串中拷贝前面num个字符到目标空间中

那么拷贝的时候是否会拷贝‘\0’呢?不会。如下图,拷贝的时候没有拷贝‘\0

int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello";
	strncpy(arr1, arr2, 3);
	printf("%s", arr1);
}

在这里插入图片描述

那如果num>源字符串的长度怎么办呢?拷贝完源字符串之后,在目标的后边追加0,直到num个

int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello";
	strncpy(arr1, arr2, 8);
	printf("%s", arr1);
}

在这里插入图片描述

6.2 模拟实现

char* my_strncpy(char* str1, const char* str2, size_t num)
{
	char* ret = str1;
	assert(str1 && str2);
	int i = 0;
	for (i = 0; i < num; i++)
	{
		*str1++ = *str2++;
	}
	return ret;
}

7.strncat

7.1 函数介绍

char * strncat ( char * destination, const char * source, size_t num );
它与strcat相比,也只是多了一个参数 size_t num,表示只从源字符串中追加前面num个字符和’\0’到目标空间中

当num<arr2的大小,会追加‘\0’

int main()
{
	char arr1[20] = "abc\0xxxxxxxx";
	char arr2[] = "hello";
	strncat(arr1, arr2, 3);
	printf("%s", arr1);
	return 0;
}

在这里插入图片描述

当num>arr2的大小呢?多余的不再起作用

在这里插入图片描述

7.2 模拟实现

char* my_strncat(char* str1, const char* str2, size_t num)
{
	char* ret = str1;
	assert(str1 && str2);
	//1.找到目标空间的末尾即'\0'位置
	while (*str1)
		str1++;
	//2.追加
	int i = 0;
	for (i = 0; i < num; i++)
	{
		*str1++ = *str2++;
	}
	*str1 = '\0';
	return ret;
}

8.strncmp

8.1 函数介绍

int strncmp ( const char * str1, const char * str2, size_t num );
它与strcmp相比,也只是多了一个参数 size_t num,表示只比较两字符串前num个字符的大小

int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "abcdqqq";
	char arr3[] = "abbb";

	int ret1 = strncmp(arr1, arr2, 5);
	int ret2 = strncmp(arr1, arr2, 3);
	int ret3 = strncmp(arr1, arr3, 3);

	printf("%d %d %d", ret1, ret2, ret3);

	return 0;
}

在这里插入图片描述

8.2 模拟实现

int my_strncmp(char* str1, char* str2, size_t num)
{
	assert(str1 && str2);
	int i = 0;
	int flag = 0;
	for (i = 0; i < num; i++)
	{
		if (*str1++ == *str2++)
		{
			flag++;
			continue;
		}
		else
			break;
	}
	if (flag == num)
		return 0;
	else
		return *str1 - *str2;
}

9.strstr

9.1 函数介绍

const char * strstr ( const char *str1, const char * str2);
若str2是str1的子串,返回str1中str2第一次出现的地址,如果str2不是str1的子串,就返回NULL

int main()
{
	char arr1[] = "abbbcd";
	char arr2[] = "bbc";
	char arr3[] = "babc";

	const char* p1 = strstr(arr1, arr2);
	const char* p2 = strstr(arr1, arr3);

	if (p1 == NULL)
		printf("找不到\n");
	else
		printf("%s\n", p1);

	if (p2 == NULL)
		printf("找不到\n");
	else
		printf("%s\n", p2);
	return 0;
}

在这里插入图片描述

9.2 模拟实现

模拟实现的函数的形参为char* str1,t char* str2,因为指向的内容不变,所以用const修饰。返回值是指针,类型为char * 。如果我们想让str1,str2指向的位置不变,那我们定义指针变量cp用来记录开始匹配的位置,指针变量s1,s2遍历str1,str2指向的字符串。让cp=str1。先考虑特殊情况,当str指向的内容为0时,返回str1指向的字符串地址。

使用while循环,当 * str1== 0时退出循环,让s1指向cp指向的位置,s2指向str2指向的位置。此时5个指针变量指向对象的图如下:
在这里插入图片描述

*s1!= * s2,cp++,s1== cp,s2==str2。

在这里插入图片描述
此时 * s1== * s2,s1++,s2++, 又* s1== * s2,s1++,s2++, * s1!= * s2,cp++,s1== cp,s2==str2。
在这里插入图片描述

此时 * s1== * s2,s1++,s2++, 又* s1== * s2,s1++,s2++,又 * s1== * s2,s1++,s2++,此时 * s2==0,表示arr2是arr1的子串,返回cp指针
在这里插入图片描述

变成代码:

const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//str1,str2让其指向的位置不变
	const char* cp = str1;//记录开始匹配的位置
	const char* s1;//遍历str1指向的字符串
	const char* s2;//遍历str2指向的字符串

	if (*str2 == '\0')
		return str1;

	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;
		cp++;
	}
	return NULL;
}

这是一种暴力求解的方式,不够高效,可以了解一下KMP算法


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

第八章 排序 六、简单选择排序

目录 一、算法思想 二、例子 1、我们有以下序列要排序 2、首先从左往右扫描&#xff0c;在其中找到最小的一个数&#xff0c;让它与第一个数互换位置 3、此次扫描完成后&#xff0c;我们取新的子序列&#xff0c;并再次从左往右扫描&#xff0c;在其中找到最小的一个数&…

makeMakefile

一、 什么是make&Makefile &#xff1f; ①make 是一条命令,makefile是一个文件,配合使用,通过依赖关系和依赖方法达到我们形成可执行程序的目的 ②makefile好处就是可以进行 自动化编译 ” &#xff0c;极大的提高软件开发的效率,一旦写好&#xff0c;只需要一个 make 命令…

推荐一款在线的JDK17中文文档

spring6.0及springboot3.0最低版本要求都是java17&#xff0c;换上java17是迟早的事&#xff0c;所以虽然我现在做的是java8&#xff0c;但是后面我想从java8直接飞升到java17&#xff0c;先做个准备&#xff0c;找到一个JDK17的中文文档&#xff0c;是在线的&#xff0c;地址&…

数据结构刷题训练——二叉树篇(一)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

学习记忆——方法篇——整除特点

理解记忆法 对于数的整除特征大家都比较熟悉&#xff1a;比如4看后两位&#xff08;因为100是4的倍数&#xff09;&#xff0c;8看后三位&#xff08;因为1000是8的倍数&#xff09;&#xff0c;5末尾是0或5&#xff0c;3与9看各位数字和等等&#xff0c;今天重点研究一下3,9,…

创新家庭办公室:打造完美工作空间的秘诀

一个精心策划的家庭办公室有很多好处&#xff0c;何不把临时工作区升级改造为你的专属工作区呢&#xff0c;还能为这些至关重要的区域注入新的活力。 创造多用途的起居室&#xff1a;我们大多数人都不曾拥有一个可以完全根据工作需求设计的独立家庭办公室——所以有时候要找到…

目标检测算法改进系列之Backbone替换为RIFormer

RIFormer简介 Token Mixer是ViT骨干非常重要的组成成分&#xff0c;它用于对不同空域位置信息进行自适应聚合&#xff0c;但常规的自注意力往往存在高计算复杂度与高延迟问题。而直接移除Token Mixer又会导致不完备的结构先验&#xff0c;进而导致严重的性能下降。 原文地址&…

Pytorch之shuffleNet图像分类

&#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 前言 ShuffleNet是Face&#xff08;旷视&#xff09;在2017年发布的一个高效率…

【傅里叶梅林图像配准】用于图像配准的傅里叶梅林相位相关性的实现(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Python之元组

Python之元组 元组tuple 一个有序的元素组成的集合使用小括号 ( ) 表示元组是不可变对象 tuple(), (), type(()) # 空元组 ((), (), tuple)(1,), (1) # 元组中只有1必须加逗号&#xff0c;否则就是1了 # ((1,), 1)x 1, 2 # 以逗号分隔的内容会形成元组&#xff0c;封装元组x…

壁炉装饰:突破传统的创新趋势

壁炉&#xff0c;一直以来都是家庭温馨的象征&#xff0c;但它也是家居装饰中一个充满潜力的元素。如今&#xff0c;随着设计趋势的不断演变&#xff0c;壁炉装饰已经迈入了一个全新的时代&#xff0c;融合了美学、功能和可持续性&#xff0c;为家庭创造了更多可能性。 壁炉装饰…

强化学习环境 - robogym - 学习 - 3

强化学习环境 - robogym - 学习 - 3 文章目录 强化学习环境 - robogym - 学习 - 3项目地址为什么选择 robogymObservation - 观测信息Action - 动作信息Initialization - 初始状态设置 项目地址 https://github.com/openai/robogym 为什么选择 robogym 自己的项目需要做一些机…

04.数据解析之css选择器

1、常见数据类型 结构化的数据是指可以使用关系型数据库表示和存储&#xff0c;表现为二维形式的数据。一般特点是&#xff1a;数据以行为单位&#xff0c;一行数据表示一个实体的信息&#xff0c;每一行数据的属性是相同的。 1、1 结构化数据 ​ 结构化的数据是指可以使用关…

策略模式与模板方法结合案例

一、背景 上周在迁移项目MQ工程的时候&#xff0c;重新Review代码&#xff0c;发现有一段代码综合使用了策略模式和模板方法&#xff0c;下面讲解一下具体场景应用的思路。 二、模板方法 策略模式前段时间有一个关于库存具体案例&#xff0c;详见 库存管理与策略模式。 模板…

智能银行卡明细筛选与统计,轻松掌握账户总花销!

作为现代生活的重要组成部分&#xff0c;银行卡成为了我们日常消费和收入的主要途径。但是&#xff0c;当我们需要了解自己的银行卡账户的总花销时&#xff0c;繁琐的明细筛选和统计工作常常让人头疼。现在&#xff0c;让我们向您推荐一款智能银行卡明细筛选与统计工具&#xf…

基于SpringBoot的学生选课系统

基于SpringBoot的学生选课系统的设计与实现&#xff0c;前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 前台主页 登录界面 管理员界面 教师界面 学生界面 摘要 学生选课系统…

halcon 数字识别

文章目录 素材交互选取区域阈值分割特征提取识别字符显示全部代码 素材 dev_get_window(WindowHandle) **读取图像 read_image(Image,C:/Users/Augustine/Desktop/1.png) **把图像转正&#xff0c;镜像方式 mirror_image(Image,ImageMirror,row) mirror_image(ImageMirror,Imag…

Python 无废话-基础知识面向对象编程详解

类定义 如何理解万物皆对象&#xff1f; 生活中一些事物&#xff0c;动物&#xff08;可爱的小狗、调皮的小猫&#xff09;、交通工具&#xff08;比亚迪U8汽车、飞机&#xff09;、人&#xff08;学生、教师&#xff09;…… 这些对象都有着独特或共性的属性和方法来描述其…

Android:实现Camera前后双摄

效果展示 一.概述 本博文讲解如何实现手机前后两颗摄像头同时预览并显示 我之前博文《OpenGLES&#xff1a;GLSurfaceView实现Android Camera预览》对单颗摄像头预览做过详细讲解&#xff0c;而前后双摄实现原理其实也并不复杂&#xff0c;粗糙点说就是把单摄像头预览流程写两…

Pytorch之MobileNetV3图像分类

&#x1f482; 个人主页:风间琉璃&#x1f91f; 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主&#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 前言 由于传统卷积神经网络&#xff0c; 内存需求大、 运算量大导致无法在移动…