【c语言:常用字符串函数与内存函数的使用与实现】

文章目录

  • 1. strlen函数
    • 1.1使用
    • 1.2模拟实现
  • 2.strcmp函数
    • 2.1使用
    • 2.2模拟实现
  • 3.strncmp函数
    • 3.1使用
    • 3.2模拟实现
  • 4.strcpy函数
    • 4.1 使用
    • 4.2模拟实现
  • 5.strcncpy
    • 5.1使用
    • 5.2模拟实现
  • 6.strcat函数
    • 6.1使用
    • 6.2模拟实现
  • 7.strncat函数
    • 7.1使用
    • 7.2模拟实现
  • 8.strstr函数
    • 8.1使用
    • 8.2模拟实现
  • 9.strtok函数
  • 10.strerror函数
  • 11.memcpy
    • 11.1使用
    • 11.2模拟实现
  • 12.memmove函数
    • 12.1使用
    • 12.2模拟实现
  • 13.memset函数
    • 13.1使用
    • 13.2模拟实现
  • 14.memcmp函数
    • 14.1使用
    • 14.2模拟实现

在这里插入图片描述

简介:本篇文章是对C语言中常用的字符串函数和内存函数的学习以及模拟实现
文档内容来自:https://legacy.cplusplus.com/

1. strlen函数

1.1使用

在这里插入图片描述

  • 字符串以 ‘\0’ 作为结束标志,
  • strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包含 '\0' )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为size_t,是无符号的( 易错
  • 使用需要包含对应的头文件<string.h>

在这里插入图片描述
下面这个代码的执行结果是什么呢?

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

strlen(str1) = 6,strlen(str2) = 3。3-6小于0,所以输出str>str2对吗?
恭喜你,掉坑里了

两个无符号数运算的结果还是无符号数,-3看成无符号数就是3,3>0所以输出str2>str1。

1.2模拟实现

  1. 定义新变量的方法
size_t my_strlen(char* str)
{size_t count = 0;while (*str){count++;str++;}return count;
}
  1. 指针-指针
size_t my_strlen(char* str)
{char* cur = str;while (*str){str++;}return str-cur;
}
  1. 不定义新变量,递归法
size_t my_strlen(char* str)
{if (*str == '\0'){return 0;}else{return 1 + my_strlen(str + 1);}
}

2.strcmp函数

2.1使用

在这里插入图片描述
在这里插入图片描述

两个字符串进行比较的时候就不能再像整数那样使用 > < = 来比较了,它实际比较的是两个字符串对应字符的ASCLL码值

  • 第⼀个字符串大于第⼆个字符串,则返回大于0的数字
  • 第⼀个字符串等于第⼆个字符串,则返回0
  • 第⼀个字符串小于第⼆个字符串,则返回小于0的数字

在这里插入图片描述

2.2模拟实现

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

3.strncmp函数

3.1使用

在这里插入图片描述

strncmp函数与strcmp函数的使用十分相似,strncmp函数只是限定了比较几个字符的大小
例如:比较前五个字符的大小
在这里插入图片描述
当要比较的长度大于两个串本身的长度时,比较到其中一个串的末尾即可
在这里插入图片描述

3.2模拟实现

int my_strncmp(const char* str1, const char* str2, int num)
{assert(str1 != NULL);assert(str2 != NULL);//无字符串可比,直接返回0if (!num){return 0;}//1.两字符串相等//2.在规定的范围内//3.字符串未到末尾while ((*str1 == *str2) && --num && *str1 != '\0'){str1++;str2++;}return *str1 - *str2;
}

4.strcpy函数

4.1 使用

在这里插入图片描述

  • 源字符串必须以 ‘\0’ 结束
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。
  • 函数返回目标空间的起始地址

在这里插入图片描述

4.2模拟实现

写法1:

char* my_strcpy(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);char* ret = dest;while (*src){*dest = *src;dest++;src++;}*dest = *src;return ret;
}

写法2:

char* my_strcpy(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);char* ret = dest;while (*dest++ = *src++){;}return ret;
}

5.strcncpy

5.1使用

在这里插入图片描述

  • 将源字符串的前 num 个字符复制到目标字符串。
  • 如果在复制 num 个字符之前找到源 C 字符串的末尾(由 null 字符表示),则 destination 将用零填充,直到总共写入 num 个字符。(不足num个,用0填充)

在这里插入图片描述

5.2模拟实现

char* my_strncpy(char* dest, const char* src, int num)
{assert(dest != NULL);assert(src != NULL);char* ret = dest;while ((*dest++ = *src++) && --num){;}while (--num){*dest = 0;dest++;}return ret;
}

6.strcat函数

6.1使用

在这里插入图片描述

  • 源字符串必须以 ‘\0’ 结束
  • 目标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。
  • 函数返回目标空间的起始地址
  • 字符串自己给自己追加,如何?(需要使用memmove)

在这里插入图片描述

6.2模拟实现

char* my_strcat(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);char* ret = dest;//找dest的\0while (*dest){dest++;}//开始追加while (*dest++ = *src++){;}return ret;
}

7.strncat函数

7.1使用

在这里插入图片描述

  • 将源的前 num 个字符附加到目标,外加一个终止 null 字符
  • 如果 source 中 C 字符串的长度小于 num,则仅复制 ‘\0’ 之前的内容
    在这里插入图片描述

7.2模拟实现

char* my_strncat(char* dest, const char* src, int num)
{assert(dest != NULL);assert(src != NULL);char* ret = dest;//找dest的\0while (*dest){dest++;}//开始追加while (num-- && (*dest++ = *src++)){;}*dest = 0;return ret;
}

8.strstr函数

8.1使用

在这里插入图片描述

  • str1中找str2字符串,返回str2第一次出现位置的地址
  • 字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志

在这里插入图片描述

8.2模拟实现

char* my_strstr(const char* str1, const char* str2)
{assert(str1 != NULL);assert(str2 != NULL);char* ptr1 = NULL;char* ptr2 = NULL;if (!(*str2)){return (char*)str1;}while (*str1){ptr1 = (char*)str1;ptr2 = (char*)str2;while ((*ptr1 == *ptr2) && *ptr1 && *ptr2){ptr1++;ptr2++;}if (*ptr2 == 0){return (char*)str1;}str1++;}return NULL;
}

9.strtok函数

在这里插入图片描述

  • delimiters参数指向⼀个字符串,定义了用作分隔符的字符集合
  • 第⼀个参数指定⼀个字符串,它包含了0个或者多个由delimiters字符串中⼀个或者多个分隔符分割的标记。
  • strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容并且可修改。
  • strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

是不是有点难理解?
用大白话说就是:

strtok函数是以一个delimiter函数中的字符为分隔依据的函数,第一次调用该函数需要将要分隔的字符串的地址传给他,它会根据分隔依据找第一次在字符串中出现该分隔符的位置,将其用\0替代,并且返回一个指向这个分隔符的指针。下一次调用就只需要传给它空指针和分隔依据,它会从上一个分隔符位置再次开始找,直到找到分隔符。最终找到字符串结尾即可。

在这里插入图片描述

10.strerror函数

strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

  • 在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0, 表⽰没有错误,
  • 当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。

strerror函数就可以将错误对应的错误信息字符串的地址返回。

打印0-10错误码对应的信息:
在这里插入图片描述
例如:我们使用fopen函数打开本地某一个文件夹,它就会自动打印处使用该函数产生的错误。
在这里插入图片描述
再我们以上所讲的所有字符串函数,你要相对字符串进行操作,是不是必须知道它的类型呀?可不是什么时候我们都能准确的知道的,比如一个结构体类型的数据。当我们不知道的时候,那么该如何操作呢?下面我们将进行讲解:

11.memcpy

11.1使用

在这里插入图片描述

  • 将 num 字节的值从源指向的位置直接复制到目标指向的内存块
  • 源指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本
  • 该函数不检查源中的任何终止 null 字符 - 它始终准确复制 num 个字节

在这里插入图片描述

11.2模拟实现

void* my_memcpy(void* dest, const void* src, int num)
{void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

12.memmove函数

12.1使用

在这里插入图片描述

  • 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。
  • 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理

在这里插入图片描述

12.2模拟实现

void* my_memmove(void* dest, const void* src, int num)
{void* ret = dest;//从前向后拷if (dest < src){while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}//从后向前拷else{while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}

13.memset函数

13.1使用

在这里插入图片描述

  • memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。
  • 将ptr指向的内存的第一个字节设置为指定的值

在这里插入图片描述

13.2模拟实现

void* my_memset(void* ptr, int x, int num)
{void* ret = ptr;while (num--){*((char*)ptr + num) = x;}return ret;
}

14.memcmp函数

14.1使用

在这里插入图片描述
在这里插入图片描述

  • 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节,
  • 如果它们都匹配,则返回零,或者返回一个不同于零的值,如果它们不匹配,则表示哪个值更大。
  • 请注意,与 strcmp 不同,该函数在找到 null 字符后不会停止比较,

在这里插入图片描述

14.2模拟实现

/*
当buf1<buf2时,返回值<0
当buf1=buf2时,返回值=0
当buf1>buf2时,返回值>0
*/
int my_memcmp(const void* buffer1, const void* buffer2, int num)
{ 当比较位数不为0时,且每位数据相等时,移动指针while (--num  && *(char*)buffer1 == *(char*)buffer2){buffer1 = (char*)buffer1 + 1;buffer2 = (char*)buffer2 + 1;}return (*(char*)buffer1) - (*(char*)buffer2);
}

目前本人学习和使用到的字符串、内存函数就这些,如有错误,请批评指正!
在这里插入图片描述

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

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

相关文章

1 NLP分类之:FastText

0 数据 https://download.csdn.net/download/qq_28611929/88580520?spm1001.2014.3001.5503 数据集合&#xff1a;0 NLP: 数据获取与EDA-CSDN博客 词嵌入向量文件&#xff1a; embedding_SougouNews.npz 词典文件&#xff1a;vocab.pkl 1 模型 基于fastText做词向量嵌入…

vue3+vite+ts项目打包时出错

项目中引入了element-plus国家化的配置&#xff0c;然后进行项目打包&#xff0c;报下面的错误 解决方法&#xff1a; 在main.ts中添加 // ts-ignore

【存储】blotdb的原理及实现(2)

【存储】etcd的存储是如何实现的(3)-blotdb 在etcd系列中&#xff0c;我们对作为etcd底层kv存储的boltdb进行了比较全面的介绍。但是还有两个点没有涉及。 第一点是boltdb如何和磁盘文件交互。 持久化存储和我们一般业务应用程序的最大区别就是其强依赖磁盘文件。一方面文件数…

Linux系统之一次性计划任务at命令的基本使用

Linux系统之一次性计划任务at命令的基本使用 一、at命令介绍二、at命令的使用帮助2.1 at命令的help帮助信息2.2 at命令的语法解释 三、at命令的日常使用3.1 立即执行一次性任务3.2 指定时间执行一次性任务3.3 查询计划任务3.4 其他指定时间用法3.5 删除已经设置的计划任务3.6 显…

深度学习毕设项目 基于生成对抗网络的照片上色动态算法设计与实现 - 深度学习 opencv python

文章目录 1 前言1 课题背景2 GAN(生成对抗网络)2.1 简介2.2 基本原理 3 DeOldify 框架4 First Order Motion Model 1 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&am…

echarts案例网站

一、ppchart 网站&#xff1a;https://ppchart.com/#/ 二、echarts官网示例 网站&#xff1a;https://echarts.apache.org/examples/zh/index.html

1992-2021年区县经过矫正的夜间灯光数据(GNLD、VIIRS)

1992-2021年区县经过矫正的夜间灯光数据&#xff08;GNLD、VIIRS&#xff09; 1、时间&#xff1a;1992-2021年3月&#xff0c;其中1992-2013年为年度数据&#xff0c;2013-2021年3月为月度数据 2、来源&#xff1a;DMSP、VIIRS 3、范围&#xff1a;区县数据 4、指标解释&a…

NeurIPS 2023|AI Agents先行者CAMEL:第一个基于大模型的多智能体框架

AI Agents是当下大模型领域备受关注的话题&#xff0c;用户可以引入多个扮演不同角色的LLM Agents参与到实际的任务中&#xff0c;Agents之间会进行竞争和协作等多种形式的动态交互&#xff0c;进而产生惊人的群体智能效果。本文介绍了来自KAUST研究团队的大模型心智交互CAMEL框…

双指针算法(题目与答案讲解)

文章目录 题目移动零复写零两数之和N数之和(>2个数) 答案讲解移动零复写零两数之和N数之和 题目 力扣 移动零 1、移动零:题目链接 复写零 2、复写零:题目链接 两数之和 3、两数之和题目链接 N数之和(>2个数) 4、N数之和(三个数、四个数) 三个数:题目链接 四个数题目链接…

Docker、Kubernetes、OCI、CRI-O、containerd、runc 之间的关系以及它们是如何一起工作的?

最近网上看到一张图片&#xff0c;能够很清晰地展现出 Docker、Kubernetes、OCI、CRI-O、containerd、runc 之间的关系以及它们是如何在一起工作的&#xff0c;如下&#xff1a; 本文可以作为之前一篇文章&#xff08;《K8s、Docker、CRI、OCI 之间的爱恨情仇》&#xff09;的…

依靠堡塔面板,飞速部署Java项目

依靠堡塔面板&#xff0c;飞速部署Java项目 环境介绍 环境介绍&#xff1a; 面板版本&#xff1a;8.0.26 操作系统版本&#xff1a;CentOS7.9.2009 Nginx版本&#xff1a;1.22 Java环境&#xff1a;Tomcat8&#xff0c;JDK&#xff1a;OpenJDK-1.8.0-internal MySQL版本&#…

CodeMeter软件保护及授权管理解决方案(二)

客户端管理工具 CodeMeter Runtime是CodeMeter解决方案中的重要组成部分&#xff0c;其为独立软件包&#xff0c;开发者需要把CodeMeter Runtime和加密后的软件一起发布。CodeMeter Runtim包括以下组件用于实现授权的使用&#xff1a; CodeMeter License Server授权服务器 Co…

7 种 JVM 垃圾收集器详解

一、概述 如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定&#xff0c;因此不同的厂商、版本的虚拟机所提供的垃圾收集器都可能会有很大差别&#xff0c;并且一般都会提供参数供用…

11月29日作业

作业&#xff1a; 自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show(…

HarmonyOS4.0开发应用(一)【工具安装】

工具安装 地址:https://developer.harmonyos.com/cn/develop/deveco-studio#download 我是windows&#xff0c;所以安装的windows 解压后双击该文件进行安装 安装完成后可选择是否导入开发工具的设置 这里选择不导入进入到工具内 点击Next进行安装 都没问题最终就可以开…

linux 脚本之条件语句 if与case

1. 测试 条件测试&#xff1a;判断某需求是否满足&#xff0c;需要由测试机制来实现&#xff0c;专用的测试表达式需要由测试命令辅助完成。 测试过程&#xff0c;实现评估布尔声明&#xff0c;以便用在条件性环境下进行执行 若真&#xff0c;则状态码变量 $? 返回0若假&am…

接口性能测试 —— Jmeter并发与持续性压测

接口压测的方式&#xff1a; 1、同时并发&#xff1a;设置线程组、执行时间、循环次数&#xff0c;这种方式可以控制接口请求的次数 2、持续压测&#xff1a;设置线程组、循环次数&#xff0c;勾选“永远”&#xff0c;调度器&#xff08;持续时间&#xff09;&#xff0c;这种…

轻松整合Knife4j:快速搭建Swagger文档界面与接口调试

Knife4j 是一个为 Java 开发者提供的 Swagger 文档聚合工具&#xff0c;它是 Swagger-Bootstrap-UI 的升级版。它的主要功能是生成和展示 API 文档&#xff0c;让开发者能够更轻松地查看和测试接口。 整合 Knife4j&#xff08;Swagger-Bootstrap-UI 的升级版&#xff09;到 Spr…

从 Elasticsearch 到 SelectDB,观测云实现日志存储与分析的 10 倍性价比提升

作者&#xff1a;观测云 CEO 蒋烁淼 & 飞轮科技技术团队 在云计算逐渐成熟的当下&#xff0c;越来越多的企业开始将业务迁移到云端&#xff0c;传统的监控和故障排查方法已经无法满足企业的需求。在可观测理念逐渐深入人心的当下&#xff0c;人们越来越意识到通过多层次、…

第三方发起备份的ORA-00245问题

文章目录 前言一、信息确认共享目录位置控制文件快照位置节点1节点2 二、RAC修改snapshot controlfile 参数三、字典表确认以及测试 前言 在使用 AnyBackup 管理控制台发起 Oracle RAC 数据库备份后&#xff0c;在任务历史记录 > 执行输出中显示如下错误信息&#xff1a; c…