在 C 语言中,字符串是以空字符('\0')结尾的字符数组,计算字符串的长度,就是计算从字符串开头到第一个空字符(不包括空字符)之间的字符个数。

(图片来源网络,侵删)
主要有以下几种方法来获取字符串长度:
- 使用标准库函数
strlen()(最常用、最推荐) - 手动编写循环计算 (用于学习和理解原理)
- 使用
sizeof运算符 (一个常见的陷阱,仅适用于栈上的字符数组)
使用标准库函数 strlen()
这是最标准、最安全、最推荐的方法。strlen() 函数定义在 <string.h> 头文件中。
函数原型
size_t strlen(const char *str);
- 参数:
str是一个指向字符串(字符数组)首地址的指针。 - 返回值: 返回字符串的长度,类型为
size_t(这是一个无符号整数类型)。 - 功能: 从
str指向的位置开始,逐个向后检查字符,直到遇到空字符'\0',然后返回已检查的字符个数(不包括'\0')。
示例代码
#include <stdio.h>
#include <string.h> // 必须包含这个头文件
int main() {
char myString[] = "Hello, C Language!";
// 使用 strlen() 计算字符串长度
size_t length = strlen(myString);
printf("字符串是: \"%s\"\n", myString);
printf("字符串的长度是: %zu\n", length); // 使用 %zu 来打印 size_t 类型
return 0;
}
输出:
字符串是: "Hello, C Language!"
字符串的长度是: 17
重要提示:strlen() 的工作原理与性能
strlen() 的工作方式是遍历字符串直到找到 '\0',这意味着:

(图片来源网络,侵删)
- 如果你的字符串很长,
strlen()就会遍历很长的距离。 - 如果你在一个循环中多次调用
strlen()来获取同一个字符串的长度,它会重复遍历多次,造成性能浪费。
最佳实践: 如果在一个循环中需要多次使用字符串的长度,最好先将长度存储在一个变量中。
// 不推荐的做法
for (int i = 0; i < strlen(myString); i++) {
// 每次循环都会调用一次 strlen(),效率低
// ...
}
// 推荐的做法
size_t len = strlen(myString);
for (int i = 0; i < len; i++) {
// 只调用一次 strlen(),效率高
// ...
}
手动编写循环计算
这种方法不依赖任何库函数,能帮助你深刻理解 C 语言中字符串的本质,核心思想和 strlen() 一样:找到 '\0' 为止。
使用 while 循环
#include <stdio.h>
// 自定义的字符串长度计算函数
size_t my_strlen(const char *str) {
size_t length = 0;
// 当指针 str 指向的字符不是空字符时,循环继续
while (*str != '\0') {
length++; // 长度加一
str++; // 指针移动到下一个字符
}
return length;
}
int main() {
char text[] = "Manual Calculation";
size_t len = my_strlen(text);
printf("字符串是: \"%s\"\n", text);
printf("手动计算的长度是: %zu\n", len);
return 0;
}
使用 for 循环
size_t my_strlen_for(const char *str) {
size_t length = 0;
// for 循环的第三个表达式可以在每次循环后执行
for (; *str != '\0'; str++) {
length++;
}
return length;
}
使用 sizeof 运算符 (一个常见的陷阱)
sizeof 运算符返回一个变量或类型所占的内存字节数,对于字符数组,它看起来像是能返回字符串长度,但这只在特定情况下才有效。
情况1:在栈上定义的字符数组
当 sizeof 用于计算一个在函数内部定义的字符数组时,它会返回整个数组的大小(包括预留的空字符 '\0' 的位置)。

(图片来源网络,侵删)
#include <stdio.h>
int main() {
char str1[] = "Hello"; // 编译器会自动在末尾添加 '\0',实际内容是 {'H', 'e', 'l', 'l', 'o', '\0'}
// sizeof(str1) 返回的是整个数组占用的字节,即 6
printf("sizeof(str1) = %zu\n", sizeof(str1)); // 输出 6
printf("strlen(str1) = %zu\n", strlen(str1)); // 输出 5
char str2[10] = "Hi"; // 数组大小为10,内容是 {'H', 'i', '\0', ... (7个未定义的字节)}
printf("sizeof(str2) = %zu\n", sizeof(str2)); // 输出 10
printf("strlen(str2) = %zu\n", strlen(str2)); // 输出 2
return 0;
}
在这个例子中,sizeof 给出了数组的总容量,而 strlen 给出了实际字符串的长度,它们是不同的。
情况2:当 sizeof 用于指针时 (陷阱!)
当你把数组名传递给函数时,它会“退化”为指向数组首元素的指针。sizeof 计算的是指针的大小,而不是数组的长度,在 64 位系统上,指针通常是 8 字节。
#include <stdio.h>
void print_size(char *s) { // s 是一个指针
printf("在函数内部 sizeof(s) = %zu\n", sizeof(s)); // 输出 8 (64位系统)
}
int main() {
char str[] = "Dangerous Trap!";
printf("在 main 函数内部 sizeof(str) = %zu\n", sizeof(str)); // 输出 18
print_size(str); // 传递数组名,函数接收到的是指针
return 0;
}
绝对不要使用 sizeof 来计算通过指针传递的字符串的长度,因为它得到的是指针的大小,而不是字符串的长度。
总结与对比
| 方法 | 描述 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
strlen() |
标准库函数,遍历到 '\0' 为止 |
标准、高效、可读性高 | 需要包含 <string.h> |
绝大多数情况下的首选 |
| 手动循环 | 自己编写循环遍历字符串 | 不依赖库,利于理解原理 | 代码冗长,容易出错 | 学习、面试、嵌入式等无库环境 |
sizeof |
计算变量或类型占用的内存大小 | 在特定情况下能快速得到数组总大小 | 不适用于字符串长度计算,极易混淆和出错 | 仅用于计算栈上数组的总容量,绝不能用于字符串长度 |
最终建议:
- 日常编程:始终使用
strlen(),并记得包含<string.h>。 - 学习理解:尝试自己实现一个
my_strlen(),弄清其背后的原理。 - 避免陷阱:牢记
sizeof和strlen的区别,不要用sizeof来计算字符串长度。
