【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

时间:2022-10-19 07:23:14

:yellow_heart: 前情提要:yellow_heart:

本章节就进入C语言的核心:深度剖析C语言库函数中的字符函数

C语言中对字符和字符串的处理很是频繁,但是C语言不像python,本身是没有字符串类型的,所以字符串通常放在常量字符串中或者字符数组中。

字符串常量适用于那些对它不做修改的字符串函数.

接下来我们即将进入一个全新的空间,对代码有一个全新的视角~

以下的内容一定会让你对C语言有一个颠覆性的认识哦!!!

<font color=gray size=3>以下内容干货满满,跟上步伐吧~

????本章重点

  • 求字符串长度

  • 长度不受限制的字符串函数

  • 长度受限制的字符串函数

<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

<b>????一.</b>求字符串函数

<b>????Ⅰ.</b>strlen函数

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

size_t strlen ( const char * str );

我们需要注意:

????strlen函数的工作原理:简单来说就是通过查找字符串中字符的个数,它将\0作为结束符号,直至找到\0截止,而且\0不计入字符个数

  • 函数的形参为:字符串的首元素地址

  • 函数的返回类型为:无符号整数

❗有了以上了解,从中得出两个点:

  • 1️⃣传进函数的字符串必须要有\0,否则字符串的个数就是随机值

  • 2️⃣计算的是字符串的个数,计算整数长度是不行的

????易错:函数的返回值为无符号整数 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

我们可以惊奇的发现:答案竟然是>

????这是因为函数的返回值为无符号整数无符号整数-无符号整数=无符号整数,所以得出的是一个很大的正整数,所以为>

  • [x] 所以日后比较的时候要注意这个点!
  • [x] 建议直接比较大小,移到比较符号左右两边,而不需要经过做减法比较

????strlen函数的模拟实现:

  • 其中模拟实现的方法有三种:

    • 1️⃣计数器的写

    • 2️⃣递归的写法【唯一不用创建变量的方法】

    • 3️⃣“指针-指针”得字符个数的写法

以下为大家介绍第三种方法:

unsigned int my_strlen(const char* str)
{
	assert(str);
	
	//要先记住初始地址
	char* ret = str;
	
	//找"\0"的地址
	while(*str++)
	{
		;
	} 
	
	return str - ret;
}

这也解释了strlen为什么只能计算字符串的个数,而不能计算整型的个数

????这是因为字符指针每次访问一个字节即一个字符时个数+1,但整型有四个字节,只有访问四次才能算作个数+1,所以不能用strlen函数去计算非字符串的个数

<b>????二.</b>长度不受限制的字符串函数

<b>????Ⅰ.</b>strcpy函数

????在前面系列文章中,已经做过strcpy函数详细的介绍和思考,欢迎大家反复学习~

????实现Strcpy函数 - 通过函数发现 “程序之美” | 不断优化、优化、再优化~

不过我们还得注意:

  • 1️⃣源字符串必须以 \0 结束

  • 2️⃣函数会将源字符串中的 \0拷贝到目标空间

  • 3️⃣目标空间必须足够大,以确保能存放源字符串

  • 4️⃣目标空间必须可变【如果目标空间指向的是常量字符串(常量字符串储存在静态区,是不可变更的),那目标空间就是不可变的】

<b>????Ⅱ.</b>strcat函数

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

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

????strcat函数的作用:字符串追加【将source指向的字符串追加到destination指向的字符串尾部】

  • 函数的形参分别为:指向目标字符串的起始地址、指向源字符串的起始地址

  • 函数的返回类型为:char*【返回的是追加后的指向目标空间的字符串起始地址,这样可以实现链式访问,更快访问追加后的字符串】

❗有了以上了解,从中得出三个点:

  • 1️⃣源字符串是从目标字符串中的\0处开始覆盖

  • 2️⃣源字符串必须以\0结尾【因为会以\0为结束的标识符,追加到\0才停止追加】

  • 3️⃣函数会将源字符串中的 \0拷贝到目标空间

????strcat函数的模拟实现

思路:

  • 实现类似于strcpy,只不过strcpy函数是在目标字符串中从头开始复制(覆盖)
  • strcat函数是先找到目标的字符串末尾\0处,再从\0这个位置开始追加(覆盖)
char* my_strcat(char*dest, const char* src)
//加上 const --- 使得更加安全【受到保护,不至于出错】
{
	char*ret = dest;

	assert(dest && src);

	//1.找目标字符串中的\0
	while (*dest) //当*dest 不等于 \0的时候,就为真
	{
		dest++;
	}//当结束循环的那一刻,*dest = \0

	//2.追加源字符串【包含了\0】
	while (*dest++ = *src++)
	{
		;
	}
	//本质上:实现原理 == strlen(目的:找到\0,即结尾处)+strcpy(目的:追加、覆盖字符)
	//官方的返回类型为 char*,同 strcpy一样,返回的都是 目标空间的起始地址

	return ret;
}

????特别注意:strcat本质上是不能自己追加自己的 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用] 因为\0被自己不断地覆盖,会导致死循环

<b>????Ⅲ.</b>strcmp函数

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

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

????strcmp函数的作用:不仅比较的是两个字符串是否相同,而更多比较两个字符串的大小

  • 函数的形参分别为:指向目标字符串的起始地址、指向源字符串的起始地址

  • 函数的返回类型为:int整型类型

➡️strcmp函数的工作原理:字符一个一个的比较【比较的是字符对应的ASCII】,当遇到一个字符串中的字符比同等位置下另外一个字符串的字符不相等时,则停止比较【即比出大小了,不用再管后面字符串还有几个字符没有比较】

❗了解以上知识后,函数的返回值之所以为整型,是因为: 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

  • 1️⃣若 str1<str2,则返回 <0的数字【在VS编译器下,返回值为-1

  • 2️⃣若 str1=str2, 则返回0【在VS编译器下,返回值为0

  • 3️⃣若 str1>str2, 则返回 >0的数字【在VS编译器,返回值为1

????strcmp函数的模拟实现:

int my_strcmp(const char*s1,const char*s2)  
//因为函数过程中仅仅是 比较,所以 不需要改变数据,直接加const即可
{
	assert(s1 && s2)

	while (*s1 == *s2)
	{
		if (*s1 == '\0') 
		//如果判断到 \0,即已经判断到末尾了,就不需要继续往后判断比较了
		{
			return 0;
		}
		
		s1++;
		s2++;
	}

	//if (*s1 > *s2)
	//{
	//	return 1;
	//}
	//else
	//{
	//	return -1;
	//}

	//可以将上面的句子 --- 优化成下列的句子
	return *s1 - *s2;
}

<b>????Ⅳ.</b>总结

✨综上:就是长度不受限制的字符串函数

➡️简单来说:就是以源字符串\0为结束标识符去做函数的工作

<b>????三.</b>长度受限制的字符串函数

<b>????Ⅰ.</b>strncpy函数

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

char * strncpy ( char * destination, const char * source, size_t num );

????strcpy函数的作用:与strcpy函数的作用一样,但多了一个参数【可自行决定复制字符串的字符个数】

  • 函数的形参分别为:指向目标字符串的起始地址、指向源字符串的起始地址、操作字符串的字符个数

  • 函数的返回类型为:char *

➡️strncpy函数的工作原理:与strcpy一样,但它可以控制拷贝num个字符从源字符串到目标字符串空间【也是从目标空间字符串的首元素地址开始拷贝(覆盖)】

❗特别注意:如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个

????由下面的调试即可看出:【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用] 1️⃣上图为:初始化两个字符数组 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]2️⃣上图为:已经完成字符串拷贝的调试,可见strncpy不仅将源字符串的\0拷贝过去,而且因为源字符串长度<num,所以剩下的由\0去补充

<b>????Ⅱ.</b> strncat函数

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

char * strncat ( char * destination, const char * source, size_t num );

????strncat函数的作用:与strcat函数一样,都是追加字符串函数【多了一个参数:负责控制追加几个字符】

  • 函数的形参分别为:指向目标字符串的起始地址、指向源字符串的起始地址、操作字符串的字符个数

  • 函数的返回类型为:char *

➡️strncat的工作原理:原理上与strcat函数一样,仅仅多了以一个函数去控制源字符串追加字符的个数

❗特别注意:

  • 1️⃣当要追加的字符个数>源字符串字符个数的时候,源字符串仅会执行到把源字符串中\0追加过去,后面便停止追加【即在这种情况下,把\0视为strncat的结束标识符】

  • 2️⃣不同于strcat函数,strcat函数视源字符串追加完自己的\0后为结束追加;但strncat函数只需要追加完num个即结束追加【???? strncat追加完后自动放上一个\0以表示追加结束 ????】

  • 3️⃣strncat函数不同于strcat函数,它可以追加自己【因为加多了一个追加字符个数的限制,就不至于在追加自己的时候陷入死循环】

????由下面的调试即可看出: 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用] 1️⃣上图为:初始化两个数组 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用] 2️⃣上图很清晰地可以看出:

  • strncat函数是从目标空间字符串的\0开始追加的

  • 即使要求追加的字符个数>源字符串的字符个数也仅仅只追加源字符串本身,多出来的num不会像strncpy那样用\0去补充

    • ????因为对于strncat不同于strncpy,它是在末尾开始追加的,又因为一般目标空间足够大,所以没必要作重复动作去用\0覆盖\0

<b>????Ⅲ.</b>strncmp

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

int strncmp ( const char * str1, const char * str2, size_t num );

????strncmp函数的作用:与strcmp的作用一样,strncmp为比较前num个字符的大小,其余跟strcmp一样

  • 函数的形参分别为:指向目标字符串的起始地址、指向源字符串的起始地址、操作字符串的字符个数

  • 函数的返回类型为:整型类型

<b>????Ⅳ.</b>总结

✨综上:就是长度受限制的字符串函数

➡️简单来说:就是比长度不受限制的字符串函数多了一个参数,使得函数长度受限制

????这样,长度受限制的字符串函数使用起来会比不受限制的更加安全,因为多了一份保障,多了一份思考,多了一份使用限制

<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

????总结

综上,我们基本了解了C语言中的 <font color=#FF69B4 >“字符函数” </font> :lollipop: <font color=black>的知识啦~~

恭喜你的内功又双叒叕得到了提高!!!

感谢你们的阅读:satisfied:

后续还会继续更新:heartbeat:,欢迎持续关注:pushpin:哟~

:dizzy:如果有错误❌,欢迎指正呀:dizzy:

:sparkles:如果觉得收获满满,可以点点赞????支持一下哟~:sparkles: 【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]