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

自己动手实现 strlen:从循环到递归的四种写法

在这里插入图片描述

🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言


🌍文章目入

    • 1. 标准库版本:拿来主义
    • 2. 计数器法:最直观的循环写法
    • 3. 指针差值法:更“C语言”的写法
    • 4. 递归法:一行代码的艺术
    • 小结对比

在 C 语言里,strlen 几乎是每个初学者都会用到的函数:它用来计算一个以空字符 \0 结尾的字符串的长度。标准库里已经有现成的实现,但自己写一遍能帮助我们理解指针、循环、递归等核心概念。

今天,我们就从标准库版本出发,一步步写出四种不同的 my_strlen,并比较它们的优缺点。


1. 标准库版本:拿来主义

#include <string.h>
int main()
{char str1[] = "abcdefg";size_t len = strlen(str1);printf("%zd\n", len);  // 输出 7return 0;
}

这是最简单的调用方式,直接使用了 <string.h> 里的 strlen 实现。


2. 计数器法:最直观的循环写法

#include <string.h>
#include <assert.h>size_t my_strlen(const char* str1)
{assert(str1);           // 防御空指针int count = 0;          // 计数器while (*str1)           // 遇到 '\0' 结束{count++;str1++;}return count;
}int main()
{char str1[] = "abcdefg";printf("%zd\n", my_strlen(str1));  // 输出 7return 0;
}

思路
从字符串首地址开始,每读到一个非零字符,计数器加 1,直到遇到 \0

优点

  • 逻辑简单,容易理解。
  • 时间复杂度 O(n),一次遍历即可。

缺点

  • 需要额外的计数器变量。

3. 指针差值法:更“C语言”的写法

#include <assert.h>size_t my_strlen(const char* str1)
{assert(str1);const char* end = str1;while (*end)           // 找到 '\0'end++;return end - str1;     // 指针 - 指针 = 元素个数
}int main()
{char str1[] = "abcdeqqqfg";printf("%zd\n", my_strlen(str1));  // 输出 10return 0;
}

思路
让指针 end 一路走到字符串末尾,两个指针相减就是中间元素的个数。

优点

  • 不需要计数器,更贴近 C 指针运算的风格。
  • 同样 O(n) 时间复杂度。

缺点

  • 可读性稍差,对初学者不够直观。

4. 递归法:一行代码的艺术

#include <assert.h>size_t my_strlen(const char* str1)
{assert(str1);if (*str1)                      // 非空字符return 1 + my_strlen(str1 + 1);return 0;                       // 遇到 '\0' 返回 0
}int main()
{char str1[] = "abcdeqqqfg";printf("%zd\n", my_strlen(str1));  // 输出 10return 0;
}

思路
把问题拆成更小的子问题:
字符串长度 = 1 + 去掉首字符后的子串长度。

优点

  • 代码极简,一行解决。
  • 逻辑优雅,适合面试炫技。

缺点

  • 递归深度等于字符串长度,可能栈溢出。
  • 每次调用都有函数开销,性能不如循环。

小结对比

实现方式时间复杂度额外空间栈深度可读性备注
计数器O(n)O(1)1★★★★☆最直观
指针差值O(n)O(1)1★★★☆☆指针风格
递归O(n)O(1)O(n)★★★★☆简洁但危险

http://www.xdnf.cn/news/15664.html

相关文章:

  • Postman/Apipost中使用Post URL编码发送含换行符参数的问题分析
  • 现代R语言机器学习:Tidymodel/Tidyverse语法+回归/树模型/集成学习/SVM/深度学习/降维/聚类分类与科研绘图可视化
  • 串口(Serial Port)是什么?
  • 在 React 中根据数值动态设置 SVG 线条粗细
  • 【52】MFC入门到精通——MFC串口助手(二)---通信版(发送数据 、发送文件、数据转换、清空发送区、打开/关闭文件),附源码
  • 9. isaacsim4.2教程-ROS加相机/CLOCK
  • vs openssl编译提示无法打开文件“libssl.lib”或“libcrypto.lib”
  • 回归预测 | MATLAB实现SA-BP模拟退火算法优化BP神经网络多输入单输出回归预测
  • 搜广推校招面经九十五
  • stm32驱动双步进电机
  • Linux入门篇学习——借助 U 盘或 TF 卡拷贝程序到开发板上
  • UniApp -- 小程序自定义导航栏组件
  • 论文征集 | 国产工业软件硕博学位论文激励计划启动
  • 主流编程语言全景图:从Python到Rust的深度解析
  • 网络基础12--可靠性概述及要求
  • sky-take-out项目Mybatis的使用
  • 高性能数据库-Redis详解
  • 网关-微服务网关入门
  • STM32-第七节-TIM定时器-3(输入捕获)
  • 深度解析Linux文件I/O三级缓冲体系:用户缓冲区→标准I/O→内核页缓存
  • 如何在服务器上获取Linux目录大小
  • Mysql数据库——增删改查CRUD
  • *SFT深度实践指南:从数据构建到模型部署的全流程解析
  • 1-大语言模型—理论基础:详解Transformer架构的实现(1)
  • LeetCode|Day18|20. 有效的括号|Python刷题笔记
  • 【数据可视化-67】基于pyecharts的航空安全深度剖析:坠毁航班数据集可视化分析
  • 小记_想写啥写啥_实现行间的Latex公式_VScode始终折叠大纲
  • 【Linux】基本指令(入门篇)(上)
  • 从0开始学习R语言--Day50--ROC曲线
  • 【深度学习】神经网络 批量标准化-part6