尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

深入解析:C重要库函数实现

深入解析:C重要库函数实现
📅 发布时间:2026/6/20 3:51:44

一.strlen实现

str的原理:它的作用是计算字符串长度,根据这个知识我们来写代码吧。

int MyStrlen(const char* s)
{int count = 0;//用于计算长度while(*s != '\0'){count++;s++;}return count;
}

其实strlen的模仿是比较简单的,只要死抓strlen是以'\0'结尾的即可,下面我用图带着大家理解一下吧。

其实就是这样的,s每次++其实就是往上移动一格,直到碰到'/0'才会停止,我们就轻松搞定了strlen的模拟实现。

二.strcpy

  strcpy的原理:将源字符串 src(包括结束符 '\0')复制到目标地址 dest 指向的内存空间中。

strcpy(char* dest,char* src)

根据strcpy的定义其实也能清楚它到底要干嘛,将src拷到dest你可以理成把src的字符一个一个拷到dest即可。

        下面我们就来实现它吧!

char* strcpy(char* des, const char* src)
{assert(des != NULL);//看是不是NULLassert(src != NULL);char* str = des;//保留des用于返回while (*src != '\0'){*str = *src;str++;src++;}*str = '\0';return des;
}

        但是这个代码其实是有槽点的很且很不安全,下面我们用图来分析这个槽点是什么
    你发现了没,如果真的要把src内容全部塞给dest那么就会导致dest访问越界,这也C语言中strcpy的一个安全隐患

三.strcmp

strcmp的原理:按字典顺序依次比较两个字符串的字符大小(即:从第一个字符开始依次往下比)前者大返回一个任意整数(我将用1代替)相等返回0,后者大返回任意一个负数(我用-1代替)

int strcmp(const char* str1, const char* str2)
{assert(str1);assert(str2);const char* s1 = str1;const char* s2 = str2;while (*s1 != '\0' && *s2 != '\0'){if (*s1 > *s2){return 1;}else if (*s1 < *s2){return -1;}else{s1++;s2++;}}if (*s1 == '\0' && *s2 =='\0'){return 0;}else if (*s1 != '\0'){return 1;}else{return -1;}
}

循环终止时,结果只能是1或-1,因为此时字符比较已出现差异。若循环未终止,则存在三种可能情况:前者字符串到达终止符'\0'、后者字符串到达'\0',或双方同时到达'\0'。

四.strstr

strstr的原理:在一个字符串(主串)中找另一个字符串(子串)首次出现的位置

char* strstr(const char* str1, const char* str2)
{assert(str1 != NULL);assert(str2 != NULL);if (!*str2)return((char*)str1);//这里强转是因为C的一个特殊的情况,就是参数是const char*返回的确实char*const char* cp = str1;const char* s1, * s2;while (*cp){s1 = cp;s2 = str2;while (*s1 == *s2 && *s2 != '\0'){s1++;s2++;}if(*s2 == '\0' )return (char*)cp;cp++;}return(NULL);
}

防止野指针与空字符串处理
assert用于确保str1和str2非空指针,避免野指针问题。若str2为空字符串,直接返回str1,因为空串是任何字符串的子串。

循环核心逻辑
外层循环通过cp遍历str1的每个字符作为匹配起点。内层循环通过s1和s2同步移动比较字符,若完全匹配(*s2 == '\0'),则返回当前cp的位置。若中途不匹配,则外层循环跳到下一个字符重新开始匹配。

可优化点说明

  1. 循环边界优化
    外层循环可限制为strlen(str1) >= strlen(str2)的情况,避免无效比较。例如str1="ab"与str2="abc"无需比较。

  2. 两层循环的必要性
    以str1="bbac"和str2="bac"为例:

  • 第一次从str1的第一个'b'开始匹配,内层比较到第二个字符'b' != 'a'失败。
  • 外层循环跳到第二个'b'重新匹配,此时内层完整匹配"bac",返回正确结果。
  1. 终止条件*s2 != '\0'的作用
    防止比较越界。例如str1="abc\0xxx"和str2="abc",当s2指向'\0'时匹配成功,若未检查可能导致s1和s2继续向后访问,引发越界。

五.memcpy

memcpy的原理:其核心是按字节,逐个复制内存数据,不关心数据的类型(因此是 “内存拷贝”)

//des:目的地,src:来源,count:拷贝几个字节
void* memcpy1(void* dst, const void* src, size_t count)
{assert(dst);assert(src);char* s1 = (char*)dst;char* s2 = (const char*)src;while (count--){*s1 = *s2;s1++;s2++;}return dst;
}

其实memcpy和strcpy原理都是差不多的,不过memcpy要实现的是任意类型,而strcpy只能实现字符类型,其实要理解这个代码只需要认识内存即可,下面我通过一张图来展示

        这里我们以整数类型为例(int n = 4)。整数类型在内存中占4个字节空间,其地址取最低位的那个字节地址。只要保证这4个字节空间连续存储即可。接下来我们重点讨论内存移动的问题。

        为什么使用void指针?可以将其理解为无类型属性(就像五行中的"无"),而其他类型都有特定属性(金、木、水、火、土)。要实现所有类型的拷贝,就需要一个能承载各种类型的通用载体,void*(无类型)显然是最合适的选择。

        但为什么又要转为char类型呢?因为void*不能直接解引用操作,只能作为载体使用。选择char类型是因为:char类型大小为1字节,因此char指针每次移动1字节这样就能确保精确控制内存移动。如果使用short(每次移动2字节),就无法正确处理char类型数据(1字节),会导致产生垃圾数据。        

        理解了这些,memcpy的工作原理就清晰了。相信聪明的你已经明白了其中的原理。

        但是这个代码是可能有问题的,至于什么问题下面我用图来展示。

你看第一张图是符合memcpy(不会出现问题)但是你看第二张图很明显出了问题,为什么呢?

其实我们根据代码可以知道,我们是用src取赋值给dst,但是如果你dst在src前面就会导致一个问题,我src把第一格的内容给了dst(src下一格)那么我在取下一格不就是src上一格的内容吗,因此就会导致问题,而这个问题就叫内存重叠。

        我们知道了memcpy当dst在src前面的时候会出现内存重叠,但是在前面多少不会出现内存重叠呢?

        其实就是保证dst不会触碰到src的地址,即dst起点>src终点。

六.memmove

memmove的出现就是为了解决内存重叠的问题的

void* memmove(void* dst, const void* src, size_t count)
{void* ret = dst;char* dst1 = (char*)dst;const char* src1 = (const char*)src;if (dst1 < src1 || dst1 > src1 + count)//确保元素修改后不在使用{while (count--){*dst1 = *src1;dst1 ++;src1 ++;}}else{dst1 = dst1 + count - 1;src1 = src1 + count - 1;while (count--){*dst1 = *src1;dst1 --;src1 --;}}return ret;
}

 从代码中可以看出,memmove 的解决方案体现在 else 语句块中。让我们分析这段代码的具体作用吧。

        memcpy 之所以会出现内存重叠问题,是因为 src 可能将自身资源复制到 src+n 的位置。这样后续操作时,src 可能会再次访问这个位置。要解决这个问题,关键在于避免 src 将资源复制到自己将要访问的位置。

        解决方案很简单:让 src 把已复制的内容全部放在目标位置之后。这样就能确保 src 不会重复处理同一个内容。

这次我讲的是面试高频率考的函数实现,希望能给大家带来帮助,如果有误可以评论我,我们抓紧修改的,希望能大家一起进步,我的一些解释采用了AI润色,希望和它的帮助下能给大家带来简洁明了的解释

相关新闻

  • 小程序/uniapp使用阿里云serverless进行oss客户端签名直传实践
  • CF241B
  • 蒟蒻入园

最新新闻

  • 品牌视觉操作系统:用AI实现可追溯、可迭代的VI设计
  • Python毕业设计-基于 Django 与协同过滤算法的图书推荐系统的设计与实现 融合协同过滤算法的智能图书推荐平台(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 2026年6月头部宠物皮肤科医院推荐,宠物眼科/猫咪体检/异宠/宠物皮肤/宠物骨科/猫咪绝育/宠物,宠物皮肤科专家找哪家 - 品牌推荐师
  • 深入解析MPC8360E/MPC8358E处理器接口电气特性与硬件设计实践
  • LLM嵌入技术在表格数据预测中的应用与实践
  • 渗透测试实战:CDN绕过与子域名爆破核心技术解析

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号