【C语言深度解剖】(12):C语言库函数的学习和模拟实现,一篇文章就够了!

🤡博客主页:醉竺

🥰本文专栏:《C语言深度解剖》

😻欢迎关注:感谢大家的点赞评论+关注,祝您学有所成!


✨✨💜💛想要学习更多C语言深度解剖点击专栏链接查看💛💜✨✨ 


目录

0. 前言

1. 函数介绍 

1.1 strlen 

1.3 strcat 

1.4 strcmp 

1.5 strncpy 

1.6 strncat 

1.7 strncmp 

1.8 strstr 

1.9 strtok

1.10 strerror 

1.11 memcpy 

1.12 memmove

1.13 memcmp

1.14 memset 

2. 库函数的模拟实现 

2.1 模拟实现strlen 

2.2 模拟实现strcpy 

2.3 模拟实现strcat

2.4 模拟实现strstr 

2.5 模拟实现strcmp 

2.6 模拟实现memcpy 

2.7 模拟实现memmove 


本章重点

重点介绍处理字符和字符串的库函数的使用和注意事项

字符串长度

  • strlen

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

  • strcpy
  • strcat
  • strcmp

长度受限制的字符串函数介绍

  • strncpy
  • strncat
  • strncmp

字符串查找

  • strstr
  • strtok

错误信息报告

  • strerror

字符操作

内存操作函数

  • memcpy
  • memmove
  • memset
  • memcmp 

0. 前言

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

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


1. 函数介绍 

1.1 strlen 

size_t strlen(const char* str);
  • 字符串已'\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
  • 参数指向的字符串必须要以 '\0' 结束。
  • 注意函数的返回值为size_t,是无符号的( 易错 ) 
  • 学会strlen函数的模拟实现

1.2 strcpy 

1.3 strcat 

将源字符串的副本附加到目标字符串。目标字符串中的终止空字符 '\0' 被源字符串的第一个字符覆盖,并返回目标字符串的起始地址。

1.4 strcmp 

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

strcmp 函数比较两个字符串 s1 和 s2,按照字典顺序(即 ASCII 值的大小)进行比较。比较过程从两个字符串的第一个字符开始,直到遇到一个不同的字符或者达到其中一个字符串的末尾。 

  • 如果 s1 和 s2 相等,返回 0。
  • 如果 s1 小于 s2(即 s1 的第一个不匹配字符的 ASCII 值小于 s2 对应字符的 ASCII 值),返回一个小于 0 的值。
  • 如果 s1 大于 s2(即 s1 的第一个不匹配字符的 ASCII 值大于 s2 对应字符的 ASCII 值),返回一个大于 0 的值。 

1.5 strncpy 

它的作用是将源字符串的一部分复制到目标字符串中,并且可以指定复制的最大字符数。 

  • dest:指向目标字符串的指针,目标字符串必须有足够的空间来保存复制的字符以及终止符 '\0'。
  • src:指向源字符串的指针,该字符串的一部分将被复制到目标字符串中。
  • n:要复制的最大字符数。如果 src 的长度小于 n,则 dest 中的剩余空间将填充为 '\0';如果 src 的长度大于或等于 n,则只有前 n 个字符会被复制到 dest 中。 

使用 strncpy 函数时,需要注意的是:

  1. 如果 src 的长度小于 n,dest 中剩余的空间将被填充为 '\0',确保目标字符串以终止符结束。
  2. 如果 src 的长度大于或等于 n,dest 不会自动添加终止符 '\0',这可能导致 dest 不是有效的 C 字符串。
  3. strncpy 不会检查 dest 的空间是否足够,因此在使用前应该确保 dest 有足够的空间。

1.6 strncat 

将源字符串的前num个字符以及一个终止的空字符追加到目标字符串。

char *strncat(char *dest, const char *src, size_t n);
  • dest:指向目标字符串的指针,目标字符串必须有足够的空间来保存附加的字符以及终止符 '\0'。
  • src:指向源字符串的指针,该字符串的一部分将被附加到目标字符串的末尾。
  • n:要附加的最大字符数。如果 src 的长度小于 n,则整个 src 会被附加到 dest;如果 src 的长度大于或等于 n,则只有前 n 个字符会被附加到 dest 中,并且 strncat 会自动在末尾添加终止符 '\0'。 

使用 strncat 函数时,需要注意的是:

  • 目标字符串 dest 必须有足够的空间来保存附加的字符以及终止符 '\0',否则可能会导致缓冲区溢出。
  • 目标字符串 dest 必须以空字符 '\0' 结尾,因为 strncat 函数会从 dest 的空字符开始附加 src。
  • strncat 不会检查 dest 的空间是否足够,因此在使用前应该确保 dest 有足够的空间。

1.7 strncmp 

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

它的作用是比较两个字符串的前 num个字符,根据比较结果返回一个整数值。

  • s1:指向第一个字符串的指针。
  • s2:指向第二个字符串的指针。
  • n:要比较的最大字符数。 

 strncmp 函数比较两个字符串 str1 和 str2 的前 num 个字符,按照字典顺序(即 ASCII 值的大小)进行比较。比较过程从两个字符串的第一个字符开始,直到遇到一个不同的字符、达到 num 个字符或者达到其中一个字符串的末尾。

strncmp 函数的返回值如下:

  • 如果 str1 和 str2 的前 n 个字符相等,返回 0。
  • 如果 s1 的前 num 个字符小于 str2 的前 num 个字符(即 str1 的某个字符的 ASCII 值小于 str2 对应字符的 ASCII 值),返回一个小于 0 的值。
  • 如果 str1 的前 num 个字符大于 str2 的前 num 个字符(即 str1 的某个字符的 ASCII 值大于 str2 对应字符的 ASCII 值),返回一个大于 0 的值。

1.8 strstr 

char * strstr ( const char *str1, const char * str2);

它的作用是在一个字符串 str1 中查找子字符串 str2 的第一次出现。如果找到子字符串,strstr 函数返回指向 str1 中子字符串第一次出现的指针;如果没有找到,返回 NULL。 

  • str1:指向要搜索的字符串的指针。
  • str2:指向要查找的子字符串的指针 

请注意,strstr 函数区分大小写,因此在搜索时它会考虑字符的大小写。如果你需要进行不区分大小写的搜索,你可能需要使用自定义函数或者库提供的其他函数。 

1.9 strtok

char * strtok ( char * str, const char * sep );

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

1.10 strerror 

char * strerror ( int errnum );
  • errnum:一个整数,表示错误码。 

strerror 函数是 C 语言标准库中的一个函数,用于将错误码转换为错误消息字符串。它的作用是根据错误码 errnum 返回一个指向描述该错误的消息的指针。 


字符分类函数: 

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者数字,a~z,A~Z,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

 字符转换:

1.11 memcpy 

void *memcpy(void *dest, const void *src, size_t n);
  • 从源内存地址 src 开始拷贝 n 个字节到目标内存地址 dest。 
  • dest 是指向用于存储拷贝内容的目标数组的指针。
  • src 是指向要拷贝的数据源的指针,src 和 dest 的类型通常是一个无类型指针(void pointer),这意味着它们可以指向任何类型的数据。
  • memcpy 拷贝指定数量的字节,不会在目标数组中添加空字符,也不会因为遇到空字符而停止拷贝。
  • n 是一个 size_t 类型的值,代表要拷贝的字节数。 

使用 memcpy 函数时需要小心,因为它不检查数组边界或重叠。如果目标和源内存区域重叠,拷贝的结果是未定义的。如果需要处理可能重叠的内存区域,应该使用 memmove 函数。 

在这个例子中,字符串 "Hello World" 被复制到 dest 数组中,包括字符串结束的空字符。函数返回的是 dest 的指针,但在实际使用中通常不需要接收这个返回值。 

1.12 memmove

void * memmove ( void * destination, const void * source, size_t num );
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理

在这个例子中,memmove将字符串 “can be very” 从索引15开始的位置复制到索引20开始的位置,覆盖了 “can be very” 后面的字符。最终打印的字符串将是 “memmove can be very useful”。

请注意,memmove和 memcpy的功能类似,但是 memcpy不保证在源地址和目标地址重叠时能正确工作,而 memmove可以。因此,当你不确定源地址和目标地址是否重叠时,应该使用 memmove来确保程序的正确性。

虽然 memmove 可以处理重叠的内存区域,但如果您确定内存区域不会重叠,使用 memcpy 函数会更高效,因为 memcpy 不会处理重叠的情况,因此通常执行速度更快。

1.13 memcmp

int memcmp(const void *ptr1, const void *ptr2, size_t num);

memcmp 是 C 语言标准库中的一个函数,用于比较两个内存块中的前 num 个字节。它按字节逐个比较两个内存块,直到遇到不同的字节或者比较完指定的字节数。

参数说明:

  • ptr1:指向第一个内存块的指针。
  • ptr2:指向第二个内存块的指针。
  • num:要比较的字节数。

返回值:

  • 如果 ptr1 和 ptr2 指向的前 num 个字节都相同,memcmp 返回 0。
  • 如果 ptr1 指向的字节大于 ptr2 指向的字节,memcmp 返回一个正数。
  • 如果 ptr1 指向的字节小于 ptr2 指向的字节,memcmp 返回一个负数。

1.14 memset 

void *memset(void *ptr, int value, size_t num);

memset 函数会将 ptr 指向的内存区域的前 num 个字节设置为 value 的值。这个函数通常用于初始化内存块,或者将内存块中的数据清零。函数的返回值是指向被设置内存区域的指针,即 ptr。 


2. 库函数的模拟实现 

2.1 模拟实现strlen 

三种方式:

方式1:计数器方式

int my_strlen(char* str)
{int length = 0;while (*str != '\0'){length++;str++;}return length;
}

方法2:(不能创建临时变量计数器)递归

int my_strlen(char* str)
{if (*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}

方法3:指针-指针的方式 

int my_strlen(char* str)
{char* start = str;while (*str != '\0'){str++;}return str - start;
}
int my_strlen(char* str)
{char* start = str;while (*str++ != '\0'){;}return str - start - 1;
}

2.2 模拟实现strcpy 

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

2.3 模拟实现strcat

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

2.4 模拟实现strstr 

char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);char* s1 = NULL;char* s2 = NULL;char* cp = (char*)str1;while (*cp){s1 = cp;s2 = (char*)str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return cp;cp++;}return NULL;
}

2.5 模拟实现strcmp 

int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}return *str1 - *str2;/*if (*str1 > *str2)return 1;elsereturn -1;*/
}
int my_strcmp(const char* src, const char* dst)
{int ret = 0;assert(src != NULL);assert(dest != NULL);while (!(ret = *(unsigned char*)src - *(unsigned char*)dst) && *dst)++src, ++dst;if (ret < 0)ret = -1;else if (ret > 0)ret = 1;return(ret);
}

2.6 模拟实现memcpy 

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

2.7 模拟实现memmove 

void* my_memove(void* dest, void* src, size_t num)
{assert(dest && src);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;
}

 到这里C语言库函数的学习基本就结束了~如果本篇文章对您有帮助,麻烦点赞收藏以及评论一下把~

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

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

相关文章

第十七篇:数据库性能优化的数学视角:理论与实践的融合

数据库性能优化的数学视角&#xff1a;理论与实践的融合 1. 引言 在现代信息技术快速发展的背景下&#xff0c;数据库性能优化已经成为计算机科学领域的一个热点问题。随着数据量的爆炸式增长和用户需求的多样化&#xff0c;数据库系统所承载的数据处理任务变得越来越复杂&…

Redis第17讲——Redis zset结构实现滑动窗口限流

一、什么是滑动窗口限流 滑动窗口限流是一种流量控制策略&#xff0c;用于控制在一定时间内允许执行的操作数量或请求频率。它的工作方式类似于一个滑动时间窗口&#xff0c;对每个时间窗口的请求数量进行计数&#xff0c;并根据预先设置的限流策略来限制或调节流量&#xff0…

maven deploy项目发布到中央仓库GPG签名失败signing failed: No secret key

maven deploy项目发布到中央仓库GPG签名失败signing failed: No secret key 执行操作 在我执行命令打包项目到中央仓库时失败 mvn clean deploy错误信息 [INFO] --- gpg:3.1.0:sign (sign-artifacts) LocalCache --- [INFO] Signing 4 files with 9961AA14xxxxxxxxxxxxxxD…

Ps 滤镜:彩色铅笔

Ps菜单&#xff1a;滤镜/滤镜库/艺术效果/彩色铅笔 Filter Gallery/Artistic/Colored Pencil 彩色铅笔 Colored Pencil滤镜用于模拟用彩色铅笔手绘的艺术效果&#xff0c;它能够在纯色背景上重新绘制图像&#xff0c;同时保留边缘细节并显示出粗糙的阴影线。此滤镜特别适合用于…

STM32HAL库-中断篇

中断 中断简介 中断是一种事件处理机制&#xff0c;可以暂停主程序的运行&#xff0c;转而处理特定事件程序。 中断的作用和意义&#xff1a; 实时控制 在确定事件内对响应事件做出相应 故障处理 检测到故障需要第一时间处理 数据传输 如串口通信&#xff0c;不确定数…

Mamba:7 VENI VIDI VICI

若在阅读过程中有些知识点存在盲区&#xff0c;可以回到如何优雅的谈论大模型重新阅读。另外斯坦福2024人工智能报告解读为通识性读物。若对于如果构建生成级别的AI架构则可以关注AI架构设计。技术宅麻烦死磕LLM背后的基础模型。 序列模型的效率与有效性之间的权衡取决于状态编…

实锤,阿里云盾会拦截百度云防护的IP!

今天凌晨&#xff0c;一位站长联系上云加速客服&#xff0c;反馈说&#xff0c;网站突然出现了502的情况。 在检查云防护子域名配置没有问题、本地强制回源没有问题的情况下&#xff0c;我们得出结论是要么服务器内防火墙拦截了云防护的IP段&#xff0c;要么服务器商拦截了云防…

分布式计算、并行计算、网格计算、边缘计算

分布式计算 分布式计算是一种计算方法&#xff0c;它将一个大型的计算任务分解成多个子任务&#xff0c;并将这些子任务分布在网络上的多台计算机&#xff08;节点&#xff09;上同时执行。这些节点通过通信网络协同工作&#xff0c;共同完成任务。每个节点可以独立处理自己的…

如何使用AzurEnum快速枚举Microsoft Entra ID(Azure AD)

AzurEnum是一款针对Azure的安全工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以轻松快速地枚举Microsoft Entra ID&#xff08;Azure AD&#xff09;。 该工具基于纯Python 3开发&#xff0c;可以在Windows和Linux系统上运行&#xff0c;但考虑到性能和稳定性&a…

远程桌面如何配置?使用快解析远程访问

远程桌面如何设置&#xff1f; 远程桌面作为windows系统内置的一个组件&#xff0c;多年来深受用户喜爱。使用此功能&#xff0c;我们能够轻而易举的控制我们想要控制的电脑。下面我就简单的介绍一下远程桌面的设置方法。 在讲具体设置方法之前&#xff0c;首先应该给大家普及…

dfs记忆化搜索,动态规划

动态规划概念&#xff1a; 给定一个问题&#xff0c;将其拆成一个个子问题&#xff0c;直到子问题可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重复计算。再根据子问题的答案反推&#xff0c;得出原问题解。 821 运行时间长的原因&#xff1a; 重复大量计算…

MLM之GPT-4o:GPT-4o(多模态/高智能/2倍速/视觉改进/128K的大窗口)的简介、安装和使用方法、案例应用之详细攻略

MLM之GPT-4o&#xff1a;GPT-4o(多模态/高智能/2倍速/视觉改进/128K的大窗口)的简介、安装和使用方法、案例应用之详细攻略 导读&#xff1a;2024年5月13日&#xff0c;OpenAI重磅发布新旗舰模型GPT-4o&#xff0c;这是一个全新的旗舰模型&#xff0c;可以实时跨越音频、视觉和…

Unity Render入门

概述 在unity中渲染相关的组件是和Render关联的&#xff0c;比如我们常见的3D模型中的MeshRender&#xff0c;UI中的RenderCanvas等都是和Render相关联的&#xff0c;相信在unity的学习过程中&#xff0c;一定看到过非常多和Render相关的内容&#xff0c;那让我们学习一下这部…

python批量生成防伪识别二维码

欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一.前言 二.代码 三.使用 四.总结 一.前言 二维码(QR Code)是一种矩阵条码技术,它使用黑白矩形图案来表示二进制数据,这些矩形图案可以被设备扫描并解读。二维码可以被用来存储

每日一题——PAT(乙级)1002 写出这个数(举一反三、思想解读)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三题目链接 我的写法&#xff1a; nums_sounds{0:ling,1:yi,2:er,3:san,4:si,5:wu,6:liu,7:qi,8:ba,9:jiu, }sum0inputsinput() input_nums[] for i i…

绝地求生:29.2商城更新内容预览:挣脱尘网通行证,经典皮肤返场,空投活动

就在今天历经9小时维护&#xff0c;29.2版本终于上线&#xff0c;柠檬茶带大家一起看看&#xff0c;这次游戏里都更新了哪些内容吧。 挣脱尘网通行证 豪华版&#xff1a;$14.99 普通版&#xff1a;$4.99 豪华版比普通版多10级升级券和2套生存者宝箱 分支一 分支二 分支三 额外…

现代加密技术(对称和非对称加密)

1.分类 现代加密技术&#xff1a;对称和非对称加密&#xff0c;对称加密即共享密钥&#xff0c;非对称加密是公钥加密算法。 2.基础总结 AES是什么算法&#xff1f; 分组加密算法&#xff0c;对称加密算法AES的分组长度是&#xff1f;固定128位AES密钥长度是多少&#xff1f;支…

树莓派3B+入门(无外设)

昨日刚到一块树莓派3B&#xff0c;甚是喜爱&#xff0c;然半宿未眠 1、下载 在官网先下载烧录文件https://www.raspberrypi.com/software/ 下载完毕打开&#xff0c;选择&#xff0c;根据自己板子型号定 操作系统用最新的就行&#xff0c;64位不太稳定 储存卡&#xff0c;需…

C++ | Leetcode C++题解之第91题解码方法

题目&#xff1a; 题解&#xff1a; class Solution { public:int numDecodings(string s) {int n s.size();// a f[i-2], b f[i-1], c f[i]int a 0, b 1, c;for (int i 1; i < n; i) {c 0;if (s[i - 1] ! 0) {c b;}if (i > 1 && s[i - 2] ! 0 &&a…

24HN逆向部分wp

24H&N逆向部分wp 菜鸡新手师傅wp&#xff0c;Re 5/9&#xff0c;记录一下qaq&#xff08;好久没写博客了&#xff0c;水一篇hh&#xff09; 最喜欢的逆向题 64位&#xff0c;进主函数之后直接看&#xff0c;要求输入第5位为i&#xff0c;然后后面依次相等&#xff0c;长…