[特殊字符] C 语言避坑指南:为什么我的 strlen 算出的是 40 而不是 10?

在 C 语言的学习过程中,字符串和数组的关系是新手最容易“翻车”的地方。今天我们来复盘一个非常经典的案例:明明数出来只有 10 个字符,为什么自定义的my_strlen函数打印结果却是 40?

这背后隐藏着一个关于内存边界结束符\0的深刻教训。

1. 案发现场还原

让我们先看看导致问题的“罪魁祸首”代码:

#include <stdio.h> size_t my_strlen(const char *p) { size_t num = 0; while(*p) { // 只要没遇到 \0 就继续数 num++; p++; } return num; } int main() { // ⚠️ 问题核心在这里:手动指定了大小为 10 char arr[10] = {"abcde fg t"}; printf("%zu", my_strlen(arr)); return 0; }

预期结果:字符串"abcde fg t"包含 5+1+2+1+1 = 10 个字符(含空格)。等等,让我们仔细数一下:a,b,c,d,e, ,f,g, ,t。一共是10个可见字符。
实际现象:用户反馈打印结果是40(或者其他的随机大数字),而不是预期的 10。

2. 深度解析:消失的\0

要理解这个问题,必须明白 C 语言字符串的两个铁律:

  1. 字符串在内存中是以空字符\0(ASCII 码为 0) 结尾的。
  2. strlen的工作原理是“向后遍历”,直到碰到\0为止,它不关心数组定义的大小,只关心内存里的内容。

让我们算一笔账:

  • 字符串内容:"abcde fg t"
  • 有效字符数:10 个。
  • 加上结束符\0:实际需要11个字节的空间。

然而,代码中定义了:

char arr[10] = ...;

数组大小只有10。这意味着编译器只能把前 10 个字符塞进去,第 11 个字节的\0被无情地截断了!

3. 为什么会是 40?

my_strlen开始工作时,它从arr[0]开始数:

  1. 它顺利地数完了数组内的 10 个字符。
  2. 因为它没找到\0,它不会停下来
  3. 它继续向高地址内存读取(数组越界访问)。
  4. 它在内存的“荒野”中继续寻找\0
  5. 直到向后读了很远(比如读了 30 个字节后),碰巧在某个内存地址上遇到了一个值为0的字节,它才停下来。

结论:那个诡异的数字40,其实是10(你的字符) + 30(内存里的垃圾数据)。这是一个典型的**缓冲区溢出(Buffer Overflow)**导致的未定义行为。

4. 正确的打开方式

为了避免这种“内存踩踏”事故,我们有两种标准的修正方案:

方案一:让编译器自动计算(推荐 ✅)
不要手动指定数组大小,让编译器根据字符串长度自动分配空间(它会自动多留一个位置给\0)。

// 编译器会自动分配 11 个字节 char arr[] = "abcde fg t";

方案二:手动预留足够空间
如果你一定要指定大小,请确保大小 > 字符串长度。

// 至少需要 11,建议给大一点,比如 20 或 64 char arr[20] = "abcde fg t";
5. 总结

在 C 语言中,。

  • 字符串长度:有效字符的个数。

一旦丢失了\0strlen就会变成一把失控的尺子,丈量到内存的尽头。希望这个“40”的教训,能让你对内存边界多一份敬畏!


这篇博客的逻辑很顺,但标题有点长。要我帮你改几个更吸睛的短标题吗?