字符串函数剖析(2)
创始人
2024-04-29 18:00:56
0

最慢的步伐不是跬步,而是徘徊;最快的脚步不是冲刺,而是坚持。——《人民日报》

在这里插入图片描述

字符串函数的重点:

文章不长,是为了让你一点点消化所有内容:
在这里插入图片描述

1.strncpy函数的脾气

  • 1.1模拟实现strncpy函数

2.strncmp函数的脾气

  • 2.1模拟实现strncmp函数

3.strncat函数的巧解

  • 3.1模拟实现strncat函数

strncpy函数

先来看一下,strncpy函数的声明:

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

与strcpy函数相比,strncpy函数只是多了一个参数:size_t num,也就是需要复制的长度

来看一下下面的例子:
在这里插入图片描述
这里是将arr2中的字符串拷贝到arr1中,指定拷贝4个,arr2不是刚好有4个字符吗,为什么会出现这样的结果呢?
在这里插入图片描述
注意看右边,arr2末尾还有一个\0未拷贝过去
在这里插入图片描述
如图:
当我们将 拷贝长度4改成5时,就可以完成了
在这里插入图片描述
所以说,strncpy函数还是比较乖的,我们让他拷贝几个,他就拷贝几个,但是,看到这里,它是真的乖吗?
再看下面,假如我把长度5改成长度10呢

在这里插入图片描述
可以发现,strncpy函数不仅帮我们将第五个改成了\0,还将超出arr2本身的长度那一部分,都改成了\0,所以,这是乖还是懂事还是自作聪明,留给你进一步探讨。

再有一个问题:
我们刚开始是将arr2拷贝到arr1中,很明显,arr2的长度小于arr1的长度,但是当我们将arr1的长度拷贝到arr2中呢?

int main()
{char arr1[] = "hello world";char arr2[] = "qwer";strncpy(arr2, arr1, sizeof(arr1)); //这里只是为了演示目标空间不够大,才写sizeof(arr1)printf("%s\n", arr1);
}

实践出真知:
在这里插入图片描述
在这里插入图片描述
翻译可得,意思就是,所拷贝的内容超出了arr2的数组的范围,造成数组越界了。
所以,strcpy的注意事项
有几点:
在这里插入图片描述

模拟实现strncpy

char* my_strncpy(char* arr1, const char* arr2, int sz)
{assert(arr1 && arr2);char* ret = arr1;while (sz &&(*arr1++ = *arr2++)!= '\0') {sz--; }if (sz) {while (--sz) //注意,如果是sz--,会多更改一次'\0'{*arr1++ = '\0';//根据strncpy函数的分析,多余的长度全部要改写成\0}}return ret;
}int main()
{char arr1[] = "hello world";char arr2[] = "qwer";char*ret = my_strncpy(arr1, arr2, 10);printf("%s\n", ret);
}

情况1:当arr1 = ‘\0’时,意味着arr2已经全部拷贝到arr1中
情况2:当sz=0时,已经完成拷贝
上面的代码是情况1,如果想出现情况2,只需将所需要拷贝的长度更改到小于源数组的长度
在这里插入图片描述
结果如上:
当我们设置成–sz时,会多更改一次’\0’,结果如下:,虽然打印出来不会改变,但是内部已经发生改变
在这里插入图片描述
arr1[10]已经被更改成了 ‘\0’

2.strncmp函数的详解

先来看一下strncmp函数的声明:

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

与strcmp函数相比,strncmp函数只是多了一个参数:size_t num,也就是所需要相比的字节的个数。

来到例题感受一下:

int main()
{char arr1[] = "abcd";char arr2[] = "abcdef";int ret =strncmp(arr1, arr2, 3);printf("%d\n", ret);
}

我们需要比较strncmp函数的前面三个字节,(由于一个字符大小是一个字节),即比较前三个字符的大小,很明显,arr1和arr2中的前三个字符的大小都相等在这里插入图片描述
由上图,当 arr1第一个字符 - arr2第一个字符时,若<0,则返回一个<0的数字,若>0,则返回一个>0的数字,若相等,则返回0;
在这里插入图片描述
所以结果一目了然。

当我们比较前5个字节时,很明显,arr1 在这里插入图片描述

模拟实现strncmp函数

int my_strncmp(const char* str1, const char* str2, unsigned int num)
{assert(str1 && str2);while (num-- && *str1 && *str1 == *str2) 三种退出循环的情况{1.num退出循环后,俩字符串相等2.*str1=='\0'时,可能相等,可能不相等3.*str1 !=*str2,必不相等str1++; str2++; }return *str1 - *str2; 不管哪种情况,退出循环之后,*str1 - *str2都能满足要求
}

重要代码部分已加解释。
下面来看一下结果:
在这里插入图片描述
这里返回-101的原因是,比较第五个字符(即第五个字节)时,arr1中的第五个字符是’\0’,arr2中的第五个字符是e,'\0’对应的ascii码值是0,e对应的ascii码值是101, 0-101 = -101
在这里插入图片描述
不管值为多少,库中的strncmp返回-1,模拟的strncmp返回-101,都小于0,都能够比较两字符串的大小。但是在visual studio环境下,strncmp和strcmp函数对于小于0或者大于0的数字,统一返回-1和1
在这里插入图片描述
在这里插入图片描述
比较一下,证明了上述的结论。所以,在模拟实现该函数时,个人认为,具体到返回的值为两个字符之间的差,更易于理解。
因为由差可以得出具体到哪两个字符不相等,差值是多少。

注意事项 -
1.目标空间必须足够大,
2.目标空间必须可修改
3.源字符串必须以’\0’结束

3.strncat函数的巧解

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

与strcat函数相比,strncat函数仍然是多了一个参数:size_t,这个参数是说:追加的字节个数。
注意,函数的追加是在\0后面追加的

来看例题感受一下:

int main()
{char arr1[20] = "hello";char arr2[] = "world";strncat(arr1, arr2, 3);
}

在arr1的\0后面追加3个字节,这三个字节来源于arr2,追加结果就是 “hellowor” ,后面默认加上了\0。

那为什么会自己在\0后面追加呢?

看一下库函数的介绍,就是在 \0 后面追加字符
在这里插入图片描述
注意:(1)当num 小于 源字符串的长度时,库函数strncat会主动加上’\0’,假如这里 num = 3,追加的时候,从arr1中的后面的\0开始追加,追加三个,即hellowor
但是在r后面,strncat会主动加上一个,就一个\0,至于后面有没有追加到num个,strncat也不管了
(2)当num 大于 源字符串的长度时,库函数strncat ,假如num = 8 ,尽管num大于arr2的长度,strncat仍然在追加完成后,主动加一个\0,且仅加一个,后面的也不管了。


我们来验证一下:
在这里插入图片描述
(1)当num小于源字符串时,会主动在最后面加上一个\0,且只加一个。
在这里插入图片描述
(2)当num大于源字符串时,会主动在最后面加上一个\0,且只加一个。
总结:
不管num大于还是小于 源字符串的长度,strncat都会主动在最后面加上一个 \0, 注意:就加一个

了解了库中的strncat函数后,我们来模拟实现my_strncat 函数

3.1模拟实现my_strncat函数

char* my_strncat(char* dest, const char* src, unsigned int num)
{assert(dest && src);char* ret = dest;while (*dest++) //不使用++*dest是因为,假如dest是一个空字符串,进入循环之后,就已经跳过了'\0',造成越界访问,发生意外{;//找到目的地字符串的\0}dest--;//退出循环后,dest指向了'\0'的后一位,所以需要dest--while (num--){if ((*dest++ = *src++) == 0){return ret;//意味着源字符串遇到\0了,已经追加完成。但是num未到0}}*dest = '\0'; // 退出循环后,表明num的值不为正数了,此时dest指向了'\0'的后一个位置,将此位置置为'\0'return ret;
}

重点部分已有注释详细介绍,根据上面对库函数的strncat的分析,我们我们需要在最后面主动加上一个 \0 .
在这里插入图片描述
可以看到,结果与预期相符。
注意:
- 1.目标空间必须足够大,
2.目标空间必须可修改
3.源字符串必须以’\0’结束

一次性看到这里,你需要回去消化一下上面的内容,不然你会吃不消,剩下的重点,我们下期见!

看到这里,如果你觉得对你有帮助,不妨关注一下,持续为你输出更高质量的知识。在这里插入图片描述

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...