模拟实现strlen()函数 (C语言)

C字符串长度 - strlen()

一、strlen() 函数概览

strlen() 是 C 标准库中用于计算字符串长度的函数,声明在 <string.h> 中。

c 复制代码
size_t strlen(const char *str);

功能

计算字符串 str 的长度,直到遇到空结束字符 '\0' 为止,但不包括 '\0'

参数

  • str:指向以 '\0' 结尾的字符串。

返回值

  • 返回字符串中字符的个数,类型为 size_t
  • size_t 是无符号整数类型,因此不要用 int 接收后直接参与可能为负的比较。

示例:

c 复制代码
#include <stdio.h>
#include <string.h>

int main(void)
{
    const char *s = "hello";
    printf("%zu\n", strlen(s)); // 输出 5
    return 0;
}

二、strlen() 的模拟实现

理解 strlen() 的最好方式之一,就是自己模拟实现它。下面给出三种常见写法。

1. 计数器方式

c 复制代码
#include <stddef.h>

size_t my_strlen(const char *str)
{
    size_t count = 0;

    while (*str != '\0') {
        ++count;
        ++str;
    }

    return count;
}

说明:

  • 从字符串首地址开始逐个字符检查。
  • 每遇到一个非 '\0' 字符,计数器加一。
  • 直到遇到 '\0' 停止。
  • 时间复杂度为 O(n)。

也可以写成:

c 复制代码
while (*str) {
    ++count;
    ++str;
}

因为 '\0' 的 ASCII 值为 0,在条件判断中相当于假。


2. 递归方式

c 复制代码
#include <stddef.h>

size_t my_strlen(const char *str)
{
    if (*str == '\0')
        return 0;

    return 1 + my_strlen(str + 1);
}

说明:

  • 如果当前字符是 '\0',说明到达字符串末尾,返回 0。
  • 否则当前字符算作 1 个长度,再递归计算后续字符串长度。
  • 代码简洁,但每次递归都会产生函数调用开销。
  • 对于非常长的字符串,可能导致栈溢出,实际工程中不推荐。

3. 指针相减方式

c 复制代码
#include <stddef.h>

size_t my_strlen(const char *s)
{
    const char *p = s;

    while (*p != '\0') {
        ++p;
    }

    return (size_t)(p - s);
}

说明:

  • p 从字符串开头向后移动,直到遇到 '\0'
  • 最终 p - s 就是两个指针之间的元素个数,即字符串长度。
  • 指针相减的结果类型是 ptrdiff_t,这里转换为 size_t 返回。
  • 这种写法简洁高效,是常见的模拟实现方式。

三种模拟实现对比

实现方式 优点 缺点
计数器 直观易懂 需要额外计数变量
递归 代码简洁 栈开销大,长字符串可能溢出
指针相减 简洁高效 需要理解指针运算

三、sizeof 与 strlen 的核心区别

sizeofstrlen 经常被初学者混淆,但它们完全不同。

对比项 sizeof strlen
本质 运算符 库函数
头文件 语言内置,无需头文件 <string.h>
计算内容 类型或对象占用的内存字节数 字符串中字符个数
是否包含 '\0' 对字符串数组/字面量通常包含 不包含
适用类型 任意类型 只能用于以 '\0' 结尾的字符串
求值时机 通常编译时,VLA 除外 运行时
返回值类型 size_t size_t
是否受数组退化影响 数组名得到数组大小,指针得到指针大小 都按指向的字符串计算

四、典型示例

c 复制代码
#include <stdio.h>
#include <string.h>

int main(void)
{
    char s1[] = "hello";
    char *s2 = "hello";
    char s3[100] = "hello";

    printf("sizeof(s1) = %zu\n", sizeof(s1)); // 6
    printf("strlen(s1) = %zu\n", strlen(s1)); // 5

    printf("sizeof(s2) = %zu\n", sizeof(s2)); // 4 或 8,取决于平台
    printf("strlen(s2) = %zu\n", strlen(s2)); // 5

    printf("sizeof(s3) = %zu\n", sizeof(s3)); // 100
    printf("strlen(s3) = %zu\n", strlen(s3)); // 5

    printf("sizeof(\"hello\") = %zu\n", sizeof("hello")); // 6
    printf("strlen(\"hello\") = %zu\n", strlen("hello")); // 5

    return 0;
}

关键点:

  • char s1[] = "hello"; 是字符数组,sizeof(s1) 包含末尾的 '\0',所以是 6。
  • char *s2 = "hello";s2 是指针,sizeof(s2) 得到的是指针大小,不是字符串长度。
  • char s3[100] = "hello"; 中数组大小固定为 100,sizeof(s3) 是 100,但 strlen(s3) 仍然是 5。

五、常见陷阱与注意事项

1. 字符串必须由 '\0' 结尾

c 复制代码
char buf[5] = {'h', 'e', 'l', 'l', 'o'};
printf("%zu\n", strlen(buf)); // 错误:buf 没有 '\0',越界访问,行为未定义

strlen() 会一直向后寻找 '\0',如果字符串没有正确终止,就会越界读取,导致未定义行为。


2. 返回类型是 size_t,不是 int

c 复制代码
if (strlen(s) - 1 >= 0) {
    // 可能永远为真
}

因为 strlen() 返回 size_tstrlen(s) - 1 仍然是无符号数。如果 strlen(s) 为 0,结果会变成一个很大的正数。

建议显式比较:

c 复制代码
if (strlen(s) > 0) {
    // ...
}

或先转换为有符号类型,但要确保长度不会溢出。


3. 函数参数中的数组会退化为指针

c 复制代码
void f(char arr[])
{
    printf("%zu\n", sizeof(arr)); // 输出指针大小,不是数组大小
}

在函数参数中,char arr[] 等价于 char *arr,所以 sizeof 得到的是指针大小。


4. strlen 不适用于二进制数据

如果数据中间可能包含 '\0',例如二进制文件内容、网络协议包等,不能使用 strlen() 计算长度。应使用 memchr() 或额外保存长度。


5. 标准库实现可能经过高度优化

标准库中的 strlen() 通常不是简单的逐字节循环,可能按机器字长读取并检测零字节,以提高性能。但语义始终不变:返回 '\0' 之前的字符数。


六、总结

  • strlen() 用于计算以 '\0' 结尾的字符串长度,不包含 '\0'
  • 可以通过计数器、递归、指针相减等方式模拟实现。
  • 工程中推荐使用标准库 strlen(),并注意其返回类型是 size_t
  • sizeof 是运算符,计算对象或类型占用的字节数;strlen 是函数,计算字符串字符个数。
  • 使用 strlen() 前必须确保字符串已经以 '\0' 正确结尾,否则会越界访问,导致未定义行为。

一句话记忆:

sizeof 看内存大小,strlen 数字符个数;sizeof 常含 '\0'strlen 不含 '\0'

相关推荐
jimy12 小时前
readelf 查看“派生类”的vtable符号
开发语言·c++
IT_陈寒2 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
分支预测失败2 小时前
RISC-V 时间子系统深度专题:mtime 访问路径、SBI 定时器与 Linux tickless 协同
后端
65岁退休Coder2 小时前
PI Agent 开发一个生产级 Harness
后端·node.js·agent
ctlover3 小时前
排序与查找算法详解
开发语言·python
用户8356290780513 小时前
如何使用 Python 给 Word 文档添加水印
后端·python
YYYing.3 小时前
【C++进阶系列 (七)】C++ RTTI 深度剖析:从 typeid 到 dynamic_cast 的底层之旅
开发语言·c++·c/c++·rtti
多弗朗皮卡丘4 小时前
数据结构9:排序算法
c语言·数据结构·排序算法
一个风轻云淡4 小时前
Markdown学习与实践
后端