当前位置: 首页 > news >正文

【C语言 模拟实现strncpy函数、strncat函数、strncmp函数、strstr函数】

C语言程序设计笔记---026

  • C语言之模拟实现strncpy函数、strncat函数、strncmp函数、strstr函数
    • 1、介绍strncpy函数
      • 1.1、模拟实现strncpy函数
    • 2、介绍strncat函数
      • 2.1、模拟实现strncat函数
    • 3、介绍strncmp函数
      • 3.1、模拟实现strncmp函数
    • 4、介绍strstr函数
      • 4.1、模拟实现strstr函数
    • 5、结语

C语言之模拟实现strncpy函数、strncat函数、strncmp函数、strstr函数

前言:
通过C语言字符串函数的知识,这篇将对strncpy、strncat、strncmp函数进行深入学习底层原理的知识,并模拟实现对应功能。

/知识点汇总/
长度不受限制的字符串函数:strcat,strcmp,strcpy
介绍长度受限制字符串函数:strncat,strncmp,strncpy
字符串查找函数:strstr

1、介绍strncpy函数

函数原型:char* strncpy(char* strDest, const char* strSource, size_t count);
函数功能:完成源字符串到目标字符串的拷贝,返回目标字符串的起始地址,返回值类型为char*,另外还可指定拷贝的长度
头文件:<string.h>
使用注意事项
(1)、源字符串必须以’\0’结束(因为会包括’\0’一起拷贝过去)
(2)、拷贝会将源字符串中的’\0’拷贝到目标空间
(3)、目标空间必须足够大,确保能存放源字符串
(4)、目标空间必须可变(不能是常量)
(5)、初始化为数组形式时,空间需要指明合适的大小
示例代码1如下

#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = { 0 };char arr2[] = "abcdefghi";strncpy(arr1, arr2, 3);printf("%s\n", arr1);//abcchar arr1[20] = "xxxxxxxxxxxxxxx";char arr2[] = "abcdefghi";strncpy(arr1, arr2, 3);printf("%s\n", arr1);//abcxxxxxxxxxxreturn 0;
}

示例代码2如下
探讨拷贝长度的因素,当指定的拷贝长度比源字符串长度大时,自动补\0

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "xxxxxxxxxxxx";char arr2[] = "abc";strncpy(arr1, arr2, 6);//6长度比str2长时,自动补的'\0'.printf("%s\n", arr1);//abc\0\0\0return 0;
}

1.1、模拟实现strncpy函数

#include <stdio.h>
#include <assert.h>
char* my_strncpy(char* str1, const char* str2, size_t num)
{assert(str1 && str2);char* ret = str1;while (num--){*str1++ = *str2++;}return ret;
}
int main()
{char arr1[] = "abcdef";char arr2[] = "defabc";printf("请输入拷贝的字符串长度:>");size_t len = 0;scanf("%zd", &len);printf("%s\n", my_strncpy(arr1, arr2,len));return 0;
}

解释说明
1.assert是断言,参数为指针,防止传参过来是空指针避免野指针的问题
2.用一个指针变量始终保存目标字符串的起始地址,以免目标起始地址发生改变,导致函数的返回值错误
3.num–执行的就是依次拷贝字符串的内容,直到num = 0,从而限制了拷贝个数,最后跳出while循环

2、介绍strncat函数

函数原型:char* strncat(char* strDest, const char* strSource, size_t count);
函数功能:完成源字符串到目标字符串的追加,返回目标字符串的起始地址,返回值类型为char*,另外还可指定追加的长度
头文件:<string.h>
使用注意事项
(1)、源字符串必须以’\0’结束(因为会包括’\0’一起追加过去)
(2)、追加会将源字符串中的’\0’拷贝到目标空间
(3)、目标空间必须足够大,确保能存放源字符串
(4)、目标空间必须可变(不能是常量)
(5)、初始化为数组形式时,空间需要指明合适的大小
示例代码1如下

#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "abc";char arr2[] = "defghi";strncat(arr1, arr2, 3);printf("%s\n", arr1);//abcdefreturn 0;
}

示例代码2如下
探究’\0’的追加情况1

#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "abc\0xxxxxxxxxxx";//字符串中本身具备'\0'时,依然以'\0'开始覆盖,最后补'\0'结束char arr2[] = "defghi";strncat(arr1, arr2, 3);printf("%s\n", arr1);//abcdef\0return 0;
}

示例代码3如下
探究’\0’的追加情况2

#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "abc\0xxxxxxxxxxx";//字符串中本身具备'\0'时,依然以'\0'开始覆盖,最后补'\0'结束char arr2[] = "defghi";strncat(arr1, arr2, 10);//10长度比str2长时,自动在末尾补'\0'.此函数就不会对超出长度的字符进行操作了printf("%s\n", arr1);//abcdefreturn 0;
}

小结
①、目标字符串中本身具备’\0’时,依然以’\0’开始覆盖,最后补’\0’结束
②、指定长度长度比源字符串长时,自动在末尾补’\0’,且此函数就不会对超出长度的字符进行操作了

2.1、模拟实现strncat函数

#include <stdio.h>
#include <assert.h>
char* my_strncat(char* str1, const char* str2, size_t num)
{assert(str1 && str2);char* ret = str1;while (*str1 != '\0'){str1++;}//*str1--;while (num--){*str1++ = *str2++;}*str1 = '\0';return ret;
}
int main()
{char arr1[10] = "abc";char arr2[10] = "abc";printf("请输入追加的字符串长度:>");size_t len = 0;scanf("%zd", &len);printf("%s\n", my_strncat(arr1, arr2, len));return 0;
}

解释说明
1.assert是断言,参数为指针,防止传参过来是空指针避免野指针的问题
2.用一个指针变量始终保存目标字符串的起始地址,以免目标起始地址发生改变,导致函数的返回值错误
3.str1 != '\0’执行的就是指针遍历目标字符串的内容,直到目标字符串的下一个地址,从而再以num–限制追加的字符长度
4.值得注意的是
str1 = ‘\0’,最后需要置结束标志位,否则就是乱码,因为直到遇见’\0’才结束。

3、介绍strncmp函数

函数原型:int strncmp( const char *string1, const char *string2, size_t count );
函数功能:字符串大小比较,返回值类型为int,另外还可指定比较的长度
头文件:<string.h>
示例代码1如下

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abcdef";char arr2[] = "abcqw";int ret = strncmp(arr1, arr2, 3);printf("%d\n", ret);//0int ret2 = strncmp(arr1, arr2, 4);printf("%d\n", ret2);//-1return 0;
}

3.1、模拟实现strncmp函数

#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* str1,const char* str2, size_t num)
{assert(str1 && str2);while (num && *str1 && *str2){if (*str1 > *str2){return 1;}if (*str1 < *str2){return -1;}num--;str1++;str2++;}return 0;
}
int main()
{char arr1[] = "abcdef";char arr2[] = "defabc";printf("请输入比较的字符串长度:>");size_t len = 0;scanf("%zd", &len);printf("%d\n", my_strncmp(arr1, arr2,len));return 0;
}

解释说明
1.assert是断言,参数为指针,防止传参过来是空指针避免野指针的问题
2.用一个指针变量始终保存目标字符串的起始地址,以免目标起始地址发生改变,导致函数的返回值错误
3.num && *str1 && *str2执行的就是依次比较字符串的内容,直到源字符串/目标字符串/指定字符长度 = 0结束,从而限制了比较字符个数,最后跳出while循环

4、介绍strstr函数

函数原型:const char *strstr( const char *string, const char *strCharSet );
函数功能:在字符串中找字符串(字符串中找子字符串或子段)
头文件:<string.h>
返回值:strstr会返回主字符串中子字符串第一次出现的位置,如果主字符串中没有子字符串,则返回NULL
示例代码1如下

#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abcdefghi";char arr2[] = "def";char* ret = strstr(arr1, arr2);if (ret == NULL){printf("找不到\n");}else{printf("%s\n", ret);//defghi}return 0;
}

4.1、模拟实现strstr函数

蛮力法,直接遍历查找

#include <stdio.h>
#include <assert.h>
const char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* cp;//记录开始匹配的位置const char* s1;//遍历str1指向的字符串const char* s2;//遍历str2指向的字符串if (*str2 == '\0')return str1;cp = str1;while (*cp){s1 = cp;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return cp;cp++;}return NULL;
}
int main()
{char arr1[] = "abcdefghi";char arr2[] = "def";const char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("找不到\n");}else{printf("%s\n", ret);//defghi}return 0;
}

解释说明
1.assert是断言,参数为指针,防止传参过来是空指针避免野指针的问题
2.定义三个指针变量,cp用于标记返回的起始地址,s1和s2用于遍历str1和str2逐个比较即可,
3.*s1 && *s2 && *s1 == *s2执行的就是依次比较字符串的内容,直到子字符串与主字符串内容匹配则结束,最后跳出while循环,返回cp的地址。

5、结语

掌握模拟函数的逻辑思维尽可能考虑全面,学会利用画逻辑图分析并一步步的推理
学习函数的最实用的方式就是用自己的逻辑简单实现一些类似的功能
半亩方糖一鉴开,天光云影共徘徊。
问渠哪得清如许?为有源头活水来。–朱熹(观书有感)

http://www.lryc.cn/news/181221.html

相关文章:

  • Mongodb7启动报错排除解决方案
  • 王杰国庆作业day5
  • QT、C++实现地图导航系统(mapSystem)
  • STM32 定时器介绍--通用、高级定时器
  • 淘宝天猫渠道会员购是什么意思?如何开通天猫淘宝渠道会员购有什么用?
  • (Note)机器学习面试题
  • 思科:iOS和iOSXe软件存在漏洞
  • CCF CSP认证 历年题目自练Day19
  • Java 开发环境配置
  • [2023.09.26]: JsValue的转换体验与as关键字的浅析
  • SpringBoot Validation入参校验国际化
  • 树莓集团涉足直播产业园区运营,成都直播产业园区再添黑马
  • 中小学教师ChatGPT的23种用法
  • Ubuntu性能分析-ftrace 底层驱动
  • 网盘搜索引擎:点亮知识星空,畅享数字宝藏!
  • Mysql以key-val存储、正常存储的区别
  • MySQL 索引优化实践(单表)
  • react create-react-app v5配置 px2rem (暴露 eject方式)
  • AVL树的实现及原理
  • NestJs和Vite使用monorepo管理项目中,需要使用共享的文件夹步骤
  • 我用PYQT5做的第一个实用的上位机项目(三)
  • 代谢组学分析平台(二)
  • 【统计学】Top-down自上而下的角度模型召回率recall,精确率precision,特异性specificity,模型评价
  • AutoDL使用tensorboard
  • 代谢组学分析手段(一)
  • 网络基础入门(网络基础概念详解)
  • 简化任务调度与管理:详解XXL-Job及Docker Compose安装
  • QByteArray字节数组
  • ubuntu20.04.3中qt程序界面嵌套另一个qt界面
  • 【chainlit】使用chainlit部署chatgpt