【深挖字符串操作】·万字总结,这些知识点你真的懂了吗?_源字符串长度大于目标字符串,strncpy会越界吗

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

char* ret = strncpy(vate1_char, vate2_char, len);
printf("%s", ret);
return 0;

}


**结果:**


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/2cca3f22061145619c799002f485137b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


**情境一分析:**



> 
> **问题1:****如果限制数len的数比源字符串的元素位数大,结果是如何?**
> 
> 
> 




> 
> **char \*strcpy( char \**strDestination*, const char \**strSource* ,size\_t  len);**
> 
> 
> 




> 
> **如果限制数len的大小比strlen(strSource)->(源字符串)大,那么strncpy函数会将源字符串中的元素拷贝到目标字符串中,而len限制数未运行的拷贝数,也将会由等量的NULL来填充。**![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/1e2170a1df2f437b96f93dc9664652b0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 




> 
> **这是函数拷贝进行时vate1\_char字符串内部的变化,而当调用结果以字符指针被传回时,在输出的过程中,只能读取到源字符串结尾的'\0',所以后面的字节都会被覆盖。**
> 
> 
> 



**vate1\_char数组内部元素摆放:**



![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/5f57ebae385242bb8432946eeefd3fa5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


**情境二分析:**



> 
> 问题2:**如果源字符串的元素位数比限制数len的数大,结果是如何?**
> 
> 
> 



> 
> **char \*strcpy( char \**strDestination*, const char \**strSource* ,size\_t  len);**
> 
> 
> 



> 
> **如果strlen(strSource)->(源字符串位数)比限制数len大时。那么,函数将依据len的大小,只拷贝源字符串中的len个数位到目标字符串中。而在结束时,不以NULL字节作为补齐,因为源字符串数位满足len限制数的调用需求,故结果将以目标字符串中的NULL为结束标志。**
> 
> 
> 


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/0fc85afa893e4592b1269e666f3ccb61.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
> **但发生源字符串大于len限制数时,那么只会拷贝源字符串中的len位,而原目标字符串中的其他数位也不会被覆盖,因为返回的结果是以原目标字符串中的NULL为结束标志。**
> 
> 
> 


**vate1\_char数组内部元素摆放:**


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/3fcef9a0d7dd4517ba285ce3f137c3fb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


**情境三分析:**



> 
> 问题3:**如果限制数len的数比目标字符串的元素位数大,结果是如何?**
> 
> 
> 



> 
> **char \*strcpy( char \**strDestination*, const char \**strSource* ,size\_t  len);**
> 
> 
> 



> 
> 当限制数len大于strlen(***trDestination)****目标字符串时,不论源字符串的数位大小满足限制数len的条件与否,都会造成最后的内存溢出与非法修改操作。最后strncpy函数会完成它本职的拷贝工作,但是你根本不知道它将溢出的数位拷贝到了哪一块内存中!*
> 
> 
> ![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/6790842803514eed9d2e659d41c01e31.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 





---



> 
> **现在再来回头看看其中的错误,其实大部分的错误都是可以被避免的,比如我们在使用拷贝函数前,先将目标字符串的大小进行合理的预留,那么bug就将减少%50!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/74a555b19b064e6697e67c76cdea3a1c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_17,color_FFFFFF,t_70,g_se,x_16)




---




> 
> **猜想:那么为什么要用NULL来填充呢?**
> 
> 
> 
> 
> 
> ---
> 
> 
> 因为,strncpy函数限制数的加入,使得函数的使用变得更灵动化。但有时候,由于错误的限制数设定,导致strncpy函数的调用结果可能并不是一个字符串。原因在于:strncpy(有限制)函数不会像strcpy函数那样,会将源字符串中的NULL也拷入进目标字符串来作为停止标记。
> 
> 
> 



> 
> 所以,strncpy函数为了避免错误的发生,它会在限制数大于源字符串数的时候触发这个保护机制,即:不够的拷贝位由NULL来补齐,以确保结果是一个能用格式化输出printf->%s来打印出。
> 
> 
> 





---


#### 


#### 


#### (3)strncpy函数的模拟实现




> 
> strncpy函数的特性:
> 
> 
> **具有限制性!**
> 
> 
> 


**上代码:**



char* my_strncpy(char* v_1, const char* v_2, int len)
{
assert(v_1 && v_2);//断言
char* ret = v_1;//将v_1首元素复制给*ret,用于返回值
while (len–)//交换一次限制数就–
{
*v_1++ = *v_2++;//拷贝
}
return ret;
}

int main()
{
char vate_1[25] = “我爱熬夜!也爱学习!”;
char vate_2[] = “我爱生活!”;
int len = 0;
puts(“请输入拷贝数:”);
scanf(“%d”, &len);
char* ret = my_strncpy(vate_1, vate_2, len);
printf(“%s\n”, ret);
return 0;
}


**结果:**


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/e7345ccd5d6f4f03a8ffa8c24f0523db.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
>  将源字符串中的5个位数拷贝至目标字符串中,可能有人会疑惑了:
> 
> 
> 




> 
> **为什么五个元素你却输入9个限制数,那岂不是拷贝了9次?**
> 
> 
> 




> 
> 其实,在最初,char类型是不允许汉字的参入的,但由于计算机语言的迅速发展,亚太地区汉语、日语、韩语等没有办法在计算机中得到参入,严重影响了功能的实现,故添加了文字。但文字与字母不同,一个汉字等同于两个字母。所以在拷贝中,需要消耗两个拷贝数才能实现一个汉字的拷贝。
> 
> 
> 




> 
> **故:2+2+2+2+1=9.**
> 
> 
> 





---


#### 


## 二、字符串追加操作




> 
> 字符串的追加操作,指的是在字符串的末尾插入另一个字符串,对目标字符串进行元素的增加。
> 
> 
> 





---


### (一)、strcat函数·(无限制)字符串追加



> 
> strcat函数是一个无限制的字符串追加函数。
> 
> 
> 



> 
> 即:给定一个目标字符串与源字符串,那么它就会将源字符串元素全部插入目标字符串。
> 
> 
> 



> 
> 这个函数的顺利进行,必须要依托'\0',且是两个字符串参数都具有NULL字节结尾。可以这么理解:
> 
> 
> 



> 
> **目标字符串中的'\0',是插入元素(源字符串)首元素的地址(入口),而源字符串的'\0'则是出口,即结束标志。**
> 
> 
> 




---


图演:


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/03fa8041026b4a4d8b0cf17f75d3de3e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/6f7c0b189ed94a6d96055151d66833be.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> 以上是strcat函数的核心作用,但这这是为了让伙伴们先简要理解以下它是干什么的,好菜还在下面呢!
> 
> 
> 





---


#### 


####  (1)strcat函数原型解析




> 
> **char \*strcat( char \**strDestination*, const char \**strSource* );**
> 
> 
> 



> 
> strcat函数的两个参数必须是以'\0'为结尾的字符序,其返回的值是一个字符指针。
> 
> 
> 



> 
> 或许有人好奇:**那如果两个参数都不为'\0'结尾的字符序结果会是如何?**
> 
> 
> 



> 
> **那么接下来就让我们实验出真理吧!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/40b5882912364704ac636f5f4a2bc3ef.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



#### (2)strcat函数的使用



> 
> 老样子,开始前,我们需要怀揣着几个问题思考:
> 
> 
> 




> 
> **1、如果strcat函数参数部分双方不为字符串,结果是如何?**
> 
> 
> **2、strcat函数可以自己(参数)调用自己(参数)吗?**
> 
> 
> 



> 
> **好戏开始!**
> 
> 
> 




---


情境一:



> 
> 如果strcat函数参数部分双方不为字符串('\0'结尾),结果是如何?
> 
> 
> 


上代码:



int main()
{
char vate_1[20] = { ‘h’,‘a’,‘p’,‘p’,‘y’};//字符数组
char vate_2[] = { ‘l’,‘i’,‘f’,‘e’};
char* ret = strcat(vate_1, vate_2);
printf(“%s\n”, ret);
return 0;
}


结果:


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/692956bf04ef4361891558b6be9e31e9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
> **持续闪烁,最后程序挂掉。**
> 
> 
> 




---



> 
> 如果给这连个非NULL结尾的字符序各自加上NULL,结果会不会有所改变 呢?
> 
> 
> 


上代码:



int main()
{
char vate_1[20] = { ‘h’,‘a’,‘p’,‘p’,‘y’,‘\0’};//在字符数组尾部添加’\0’
char vate_2[] = { ‘l’,‘i’,‘f’,‘e’,‘\0’};
char* ret = strcat(vate_1, vate_2);
printf(“%s\n”, ret);
return 0;
}


结果:


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/e4db6360d9244ed0a9f4f26254a80ff8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
> ***最后确实达到了我们的预期,但这是为什么呢?***
> 
> 
> 




---


情境二:



> 
> strcat函数可以自己(参数)调用自己(参数)吗?
> 
> 
> 


上代码:



int main()
{
char vate_1[20] = “happy”;
char vate_2[] = “life”;
char* ret = strcat(vate_1, vate_1);
printf(“%s\n”, ret);
return 0;
}


结果:


![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/f583ec86b32740b6a3fc7c97456cc5ad.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> **接下来开始解析,小伙伴们,能看到这已经很棒啦!但请继续坚持,我保证最后你将会有所收获!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/ea2ba24e17f74d8a94241b9d4cbf0ff9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_17,color_FFFFFF,t_70,g_se,x_16)




---



情境1解析:



> 
> 问题:如果strcat函数参数部分双方不为字符串('\0'结尾),结果是如何?
> 
> 
> 



> 
> 如果stact函数的两个参数都不以NULL字节结束,那么,可怜的strcat函数根本就找不到进行的入口,更不要想出口在哪里,所以它一直在寻找目标字符串中的NULL字节,等到最后确实找不到了,那么这个函数也就挂了!
> 
> 
> 



> 
> 尽管幸运找到那两个入口与出口,那么所返回的值也必定是非法的!
> 
> 
> ![watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16](https://img-blog.csdnimg.cn/7f838e594cb34803ac6f3395b584d2ec.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 



> 
> 而上述最后所作的修改:是在目标字符序与源字符序中各添加“NULL”字节,有了入口与出口,strcat函数就满血复活啦!
> 
> 
> 




---


情境2解析:



> 
> **strcat函数可以自己(参数)调用自己(参数)吗?**
> 
> 
> 



> 
> 这里出现了一个有趣的例子,也是对strcpy函数的挑战。strcat函数能够对目标字符串进行直接的改动,而在情境二中:strcat函数首先找到vate\_1的NULL字节,将其修改为源字符串的首元素:'h',注意!strcat函数能够对目标元素进行直接的修改,这就意味着作为参数的源字符串vate\_1中的NULL字节也被修改为了:'h',
> 
> 
> 



> 
> 之前我们提到:目标字符串中的NULL字节,相当于strcat函数的一个切入点,即:“入口”,而源字符串中的NULL字节则相当于一个结束标志,即:“出口”。而上述情况则相当于函数有了入口,却没了出口!
> 
> 
> 



> 
> 那会发生什么情况呢?答案一定是内存的越界操作,可怜的strcat函数在苦苦的寻找那个出口,但久久未能找到,最后导致程序崩溃!
> 
> 
> ![](https://img-blog.csdnimg.cn/a7dc9089d4904c37937d39985033852d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 



> 
> 依据strcat函数的运行原理,它无法完成对同一字符序的自我追加操作,但strncat函数则对此进行了修善,待完成strcat函数的模拟实现后,我们就见分晓!
> 
> 
> 




---


#### (3)strcat函数的模拟实现



> 
> **char \*strcat( char \**strDestination*, const char \**strSource* );**
> 
> 
> 



> 
> 我们举了两个strcat函数的使用情境,对此,从中我们可以总结出:
> 
> 
> 



> 
> strcat函数在目标字符串结束符“NULL”上进行插入,将源字符串的首元素覆盖掉NULL字节,并逐个向后访问,直到找到源字符串尾部的NULL字节,并将其插入至目标字符串尾部后,函数才会停止。
> 
> 
> 



> 
> 接下来,我们就以此总结为实现目标,完成对strcat函数的模拟实现:
> 
> 
> 


上代码:



//strcat模拟实现
char* my_strcat(char* value1_char, const char* value2_char)
{
assert(value1_char && value2_char);
char* temp = value1_char;//储存目标字符串的首地址
while (*value1_char)//寻找目标字符串’\0’
{
value1_char++;
}
while (*value1_char++ = *value2_char++)//在’\0’位置进行源字符串的拷贝
{
;
}
return temp;//返回
}

int main()
{
char value1_char[50] = “我热爱生活!也热爱学习!”;
char value2_char[] = “愿世间充满欢乐!”;
char* temp = my_strcat(value1_char, value2_char);
printf(“%s”, temp);
return 0;
}

//理解及思路
//1、保证目标字符串及源字符串的结尾都具备有‘\0’。
//2、目标字符串空间须是可修改的,且是足够大的。
//3、第一步需要找到目标字符串的‘\0’处。
//4、第二步,在目标字符串‘\0’处进行进行拷贝,将源字符串拷贝到目标字符串之后,直到’\0’结束。
//5、需要对目标字符串进行存地址,否则贸然返回目标字符串,所得到的将是尾部’\0\的地址,从而导致空白打印。



结果:


![](https://img-blog.csdnimg.cn/0bf130d344d74dfdbfe3a615d600a64e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
> **在这喧嚣内卷的世界中,我愿拼尽全力,去创那三分自留地,护一家长幼安详,与她安稳相守。也祝你们顺利!**
> 
> 
> 




---


#### (5)strcat函数的缺陷



> 
> 要说strcat的缺陷,其实只要有两点:
> 
> 
> 




> 
> **1、不能作用与同一个参数的调用。**
> 
> 
> **2、不具备灵活调控性。**
> 
> 
> 





---


#### 


### (二)、strncat函数·(有限制)字符串追加




> 
> strncat函数也加入了限制数,因为限制数的加入,使得strcat函数不再像是一匹充满野性的野马,不受控制,反之它将被我们很好的使用。
> 
> 
> 





---


#### 


#### (1)strncat函数原型解析




> 
> **char \*strncat( char \**strDest*, const char \**strSource*, size\_t *count* );**
> 
> 
> 



> 
> **与上方所探索的strncpy很相似,它是控制拷贝数。而strncat函数的限制数,则是用来控制追加数的,知识点可以互通,相信看到这里伙伴们早已经有了思路!**
> 
> 
> 



> 
> **接下来就让我们实验出真理吧!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/ab61a5328a1d4f189657eb2ca12e5a72.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



#### (2)strncat函数的使用



> 
> 带着这两个问题进入以下环节:
> 
> 
> 




> 
> **1、strncat函数可以作用于同一个参数吗?**
> 
> 
> **2、如果限制数比原字符串参数数位:“大了”或者“小了”会如何?**
> 
> 
> 




---


情境一:           



> 
>       strncat函数可以作用于同一个参数吗?
> 
> 
> 


上代码:



//strncat函数可以作用于同一个参数吗?
int main()
{
char vate_1[20] = “joy”;
char vate_2[] = “and sadness”;
int count = 0;
puts(“请输入追加数:”);
scanf(“%d”, &count);//限制数输入:4
char* ret = strncat(vate_1, vate_1, count);
printf(“%s\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/671fbfcd5eb14d73a05bb307acd7c1b2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


情境二:



> 
>  如果限制数比原字符串参数数位:“大了”或者“小了”会如何?
> 
> 
> 




---


(限制数大于源字符串位数)上代码:



//限制数大于源字符串位数,会发生什么?
int main()
{
char vate_1[20] = “joy”;
char vate_2[] = " and sadness";
int count = 0;
puts(“请输入追加数:”);
scanf(“%d”, &count);//限制数输入值:50
char* ret = strncat(vate_1, vate_2, count);
printf(“%s\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/2afffd113f5a4e1bab862e029bb59211.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---


 (限制数小于源字符串位数)上代码:



//限制数小于源字符串位数,会发生什么?
int main()
{
char vate_1[20] = “joy”;
char vate_2[] = " and sadness";
int count = 0;
puts(“请输入追加数:”);
scanf(“%d”, &count);//限制数输入值:3
char* ret = strncat(vate_1, vate_2, count);
printf(“%s\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/9dabf0d80ee44d26b5f367c714ce31f5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)





---




---


情境一解析:



> 
> **strncat函数可以作用于同一个参数吗?**
> 
> 
> 



> 
> 这是一个很刁钻的角度,因为如果按照strcat函数的运作来说,这无疑将是一个无法解决的难题。但strncat对此进行了优化。
> 
> 
> 



> 
> 在两个参数都为同一字符串的情况下,追加无疑会改变参数本身元素,而缺少了一个源字符串末尾NULL字节的出口,无疑又会面临着死循环的问题。
> 
> 
> 



> 
> **所以,当strncat函数中的限制数为0时,它就会给追加目标数据的末尾加上一个NULL字节。**
> 
> 
> 


![](https://img-blog.csdnimg.cn/88cc761338794f01b9092ea794ba2565.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)





---


情境二解析:



> 
> **如果限制数比原字符串参数数位:“大了”或者“小了”会如何?**
> 
> 
> 



> 
> 面对这种情况,我们可以很轻松的去理解它:
> 
> 
> 




> 
> **1、当限制数大于源字符串时:其会先将源字符串全部追加至目标字符串中,但源字符串末尾蕴含NULL字节,所以会停止。**
> 
> 
> 



> 
> **2、但限制数小于源字符串时:其会追加限制数要求的几个数位,若限制数为0,那么将为目标字符串末尾追加NULL字节。**
> 
> 
> 




---


#### (3)strncat函数的模拟实现


上代码:



//strncat函数模拟实现
char* my_strncat(char* v_1, const char* v_2, size_t count)
{
assert(v_1 && v_2);//断言判断是否为空指针
char* ret = v_1;//将目标字符串首地址赋值给字符指针:ret用作返回值
while (*v_1)
{
v_1++;//找到目标字符串参数中的’\0’(找到:入口)
}
while ((count–))//限制数为0时停止
{
if ((*v_1++ = *v_2++) == ‘\0’)
//当v_1为’\0’时返回指针。
//此情况是在两个参数都为NULL字节结束的情况下发生
{
return ret;
}
}
v_1 = ‘\0’;
//而在末尾补NULL字节是在源字符序结尾不为NULL字节时,或同一参数追加时进行。
return ret;
}
int main()
{
char vate_1[25] = “道阻且长,”;
char vate_2[] = “行则将至!”;
char
ret = my_strncat(vate_1, vate_2, 100);
printf(“%s\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/5c678661cbe143f89ed93e52b63c262c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)





---


## 三、字符串比较操作



> 
> 字符串比较是字符串操作常用到的一种解法,它用于比较两个字符串之间(无限制)或两个字符串中指定元素(有限制)的大小。
> 
> 
> 




---


### (一)、strcmp函数·(无限制)字符串比较



> 
> strcmp函数用于比较两个字符串之间的大小,至于是如何进行比较的、及依据什么去判断的?我们接下来开始探索:
> 
> 
> 




---


#### (1)strcmp函数原型解析



> 
> **int strcmp( const char \**string1*, const char \**string2* );**
> 
> 
> 



> 
> strcmp函数的两个参数是字符指针,它所返回的值是:int(整形)。在函数内部规定了以下标准:
> 
> 
> 



> 
> **1、当(目标字符串)string\_1 > (源字符串)string\_2 时, 返回大于0的数。**
> 
> 
> **2、当(目标字符串)string\_1 < (源字符串)string\_2 时, 返回小于0的数。**
> 
> 
> **3、当(目标字符串)string\_1 ==(源字符串)string\_2 时, 返回0。**
> 
> 
> 



> 
> 那么它究竟是怎么判断的呢?请看图演:
> 
> 
> ![](https://img-blog.csdnimg.cn/6d226f532a874aa7b29f7819c35554d7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> ![](https://img-blog.csdnimg.cn/f100daa21e3b496fb55b1c92d590c5b8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> ![](https://img-blog.csdnimg.cn/7190ee4f99fd46baba7ca41cb7d3e823.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 



> 
> **而字符比较大小的依据,则取决于ASCII码值,逐个进行大小的比对。**
> 
> 
> 




---


#### (2)strcmp函数的使用



> 
> **int** **strcmp(** **const** **char** **\****string1*, **const** **char** **\****string2* **);**
> 
> 
> 



> 
> 接下来我们就来使用strcmp函数,而在此函数中,博主只有一个问题:
> 
> 
> 



> 
> **strcmp函数能对汉字进行大小的比较吗?**
> 
> 
> 



> 
> **我们实践出真理吧!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/b6f78fd8691746d09a382449802ee288.gif)




---



上代码:



> 
> 比较:张三与李三
> 
> 
> 



//strcmp函数能否比对汉字的大小?
//张三与李三
int main()
{
char v_1[] = “张三”;
char v_2[] = “李三”;
int ret = strcmp(v_1, v_2);
printf(“%d\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/2c5db99278234c99ae97490b434d9be2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> 比较:李三与张三
> 
> 
> 



//strcmp函数能否比对汉字的大小?
//李三与张三
int main()
{
char v_1[] = “李三”;
char v_2[] = “张三”;
int ret = strcmp(v_1, v_2);
printf(“%d\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/964f8f4e76724bbdaf82036d3a8fb9e7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> 比较:张三与张三 
> 
> 
> 



//strcmp函数能否比对汉字的大小?
//张三与张三
int main()
{
char v_1[] = “张三”;
char v_2[] = “张三”;
int ret = strcmp(v_1, v_2);
printf(“%d\n”, ret);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/517beae695784014bc7758c5ff0c2eb7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> 猜想:我无法相信strcmp函数能够依据汉字的拼音首字母进行解读,毕竟中华文化博大精深。但我也还未清楚它是如何做到的。但我觉得它可能是以汉字的二进制,来作为判断标准进行比较。
> 
> 
> 



> 
> **希望知道的大佬能够在评论区解答!**
> 
> 
> 


![](https://img-blog.csdnimg.cn/7adc8eee4a6f49a3a3cc93f000419144.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



#### (3)strcmp函数的模拟实现


上代码:



//strcmp比较字符串
int my_strcmp(const char* value1_char, const char* value2_char)
{
assert(value1_char && value2_char);//断言
while (*value1_char == *value2_char)//当两位数比较不同时退出
{
if (*value1_char == ‘\0’ && *value2_char == ‘\0’)//如果俩字符串同时找到\0,那么就相等
{
return 0;//返回0
}
value1_char++;//如果每一位相等,那么各自向后移动一位,直到找到\0,或不同
value2_char++;
}
return *value1_char - *value2_char;//如果不同则返回目标位-源字符串位,依据结果判断大小
}

int main()
{
char value1_char[] = “good”;
char value2_char[] = “good”;
int temp = my_strcmp(value1_char, value2_char);
if (temp > 0)//判断
{
puts(“>”);
}
else if (temp < 0)
{
puts(“<”);
}
else
{
puts(“==”);
}
printf(“%d”, temp);
return 0;
}


结果:


![](https://img-blog.csdnimg.cn/3352b6ed94884e028464258757658e04.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
>  如何实现都在代码注释里啦!
> 
> 
> 




---


#### (4)strcmp函数的缺陷



> 
> strcmp函数在运行过程中,无需进行任何的数据修改,只要进行两个字符串之间的比较,所以,内存上的常出bug不会出现,如果一定要揪出来问题,那只有这个了:
> 
> 
> 



> 
> **缺乏灵活性**
> 
> 
> 




---


### (二)、strncmp函数·(有限制)字符串比较



> 
> 同样的,有限制就意味着“限制数”的存在。即:我们需要对字符串元素进行比较的数位。
> 
> 
> 




---


#### (1)strncmp函数原型解析



> 
> **int strncmp( const char \**string1*, const char \**string2*, size\_t *count* );**
> 
> 
> 



> 
> 这里要注意的是:count指的是将要进行比较的元素数位,即从首位到count位。
> 
> 
> 




---


#### (2)strncmp函数的使用



> 
> 在开始前,有一个问题:
> 
> 
> 



> 
> **如果在对比中,在count的范围内有多处错误,函数该怎么判断先后?**
> 
> 
> 



> 
> 为了更具有视觉辩证性,我将不采用库函数中的strncmp进行演示,因为库中此函数总是将:
> 
> 
> 




> 
> **1、大于的返回值为:1**
> 
> 
> **2、小于的返回值为:-1**
> 
> 
> **3、等于的返回值为:0**
> 
> 
> 



> 
> 这样无法弄清,函数是怎么判断错误的先后性,所以,这里就不作库函数的使用演示了,通过以上的个例大家早已经融会贯通,那么接下来就让我们开始 吧!
> 
> 
> 




---


#### (3)strncmp函数的模拟实现



> 
> 问题:
> 
> 
> 




> 
> **在对比中,count的范围内有多处错误,函数该怎么判断先后呢?**
> 
> 
> 



> 
> 测试:count = 1~6,且字符串比较中存在三个错误
> 
> 
> 



> 
> 错误点:
> 
> 
> **1、第三个元素:‘f'与'c'**
> 
> 
> **2、第四个元素:'d'与'e'**
> 
> 
> **3、第五个元素:’e'与'f'**
> 
> 
> 


上代码:



//strncmp函数的模拟实现
int my_strncmp(const char* v_1, const char* v_2, int temp)
{
assert(v_1 && v_2);//判断两个参数是否为空指针
while ((–temp) && (*v_1 == *v_2))//如果temp为0 并且 *v_1 != *v_2时退出循环
{
if (*v_1 == ‘\0’ && v_2 == ‘\0’)//如果v_1 && *v_2同时等于/0则代表相等
{
return 0;//返回0
}
v_1++;//逐个向后
v_2++;
}
return *v_1 - *v_2;//如果某元素不相等则直接返回,*v_1-*v_2
}

int main()
{
char vate1_char[] = “abfdef”;
char vate2_char[] = “abceff”;
int temp = my_strncmp(vate1_char, vate2_char, 6);//测试1~6之间
if (temp > 0)//判断部分
{
puts(“vate1_char > vate2_char”);
}
else if (temp < 0)
{
puts(“vate1_char < vate2_char”);
}
else
{
puts(“vate1_char == vate2_char”);
}
printf(“%d”, temp);
return 0;
}




---


**结果:**




---



> 
> count = 1
> 
> 
> vate1\_char(‘a') == vate2\_char(‘a')
> 
> 
> 


![](https://img-blog.csdnimg.cn/206b554cca9d40bfa5ee293c3965af47.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)





---



> 
> count = 2
> 
> 
> vate1\_char(‘b') == vate2\_char(‘b')
> 
> 
> 


![](https://img-blog.csdnimg.cn/927cb647b5024181abb6cc51056cbf43.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
>  count = 3
> 
> 
> vate1\_char(‘f') > vate2\_char(‘c')
> 
> 
> ('f'(102) - 'c'(99))  = 3
> 
> 
> 


![](https://img-blog.csdnimg.cn/4ad66867253b47cf976cecd4b062bf01.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> **count = 4**
> 
> 
> **vate1\_char(‘d') < vate2\_char(‘e')**
> 
> 
> **('d'(100) - 'e'(101))  = -1**
> 
> 
> 


![](https://img-blog.csdnimg.cn/3e3472ba87bd40bda50f685d02aae881.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> **count = 5**
> 
> 
> **vate1\_char(‘e') < vate2\_char(‘f')**
> 
> 
> **('e'(101) - 'f'(102))  = -1**
> 
> 
> 


![](https://img-blog.csdnimg.cn/2d533e855e004080b14453c80bcd7434.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
>  **count = 6**
> 
> 
> **vate1\_char(‘f') == vate2\_char(‘f')**
> 
> 
> **('f'(102) - 'f'(102))  = 0**
> 
> 
> 


![](https://img-blog.csdnimg.cn/ad677cf4813341b8bd567cb29e38f5b7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---




---



> 
> 总结:count = 3时,是第一个错误点。但在之后,不论限制数怎么增加,错误总是停留在上方的第三个元素位。所以,我们得出结论:
> 
> 
> 



> 
> strncmp函数在遇到第一个错误点时就会停止并返回!
> 
> 
> 




---


![img](https://img-blog.csdnimg.cn/img_convert/b245546fbb36fe6d4abdbb56a7af5fdc.png)
![img](https://img-blog.csdnimg.cn/img_convert/336cf972abab2c921dd2a0f0c5be50e6.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

TiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
>  count = 3
> 
> 
> vate1\_char(‘f') > vate2\_char(‘c')
> 
> 
> ('f'(102) - 'c'(99))  = 3
> 
> 
> 


![](https://img-blog.csdnimg.cn/4ad66867253b47cf976cecd4b062bf01.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> **count = 4**
> 
> 
> **vate1\_char(‘d') < vate2\_char(‘e')**
> 
> 
> **('d'(100) - 'e'(101))  = -1**
> 
> 
> 


![](https://img-blog.csdnimg.cn/3e3472ba87bd40bda50f685d02aae881.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
> **count = 5**
> 
> 
> **vate1\_char(‘e') < vate2\_char(‘f')**
> 
> 
> **('e'(101) - 'f'(102))  = -1**
> 
> 
> 


![](https://img-blog.csdnimg.cn/2d533e855e004080b14453c80bcd7434.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---



> 
>  **count = 6**
> 
> 
> **vate1\_char(‘f') == vate2\_char(‘f')**
> 
> 
> **('f'(102) - 'f'(102))  = 0**
> 
> 
> 


![](https://img-blog.csdnimg.cn/ad677cf4813341b8bd567cb29e38f5b7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARHVvbmku,size_20,color_FFFFFF,t_70,g_se,x_16)




---




---



> 
> 总结:count = 3时,是第一个错误点。但在之后,不论限制数怎么增加,错误总是停留在上方的第三个元素位。所以,我们得出结论:
> 
> 
> 



> 
> strncmp函数在遇到第一个错误点时就会停止并返回!
> 
> 
> 




---


[外链图片转存中...(img-EORpNycS-1715791119398)]
[外链图片转存中...(img-CwVGO7BH-1715791119399)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值