在C语言中,计算字符串长度是一个基本且常见的操作,字符串是以空字符 '\0' 结尾的字符数组,计算字符串长度就是计算从字符串开头到 '\0' 之前的字符个数。

(图片来源网络,侵删)
下面我将从几个方面详细解释如何在C语言中获取字符串长度。
使用标准库函数 strlen()
这是最常用、最简单、最推荐的方法。strlen() 函数在 C 标准库 <string.h> 中定义。
函数原型
size_t strlen(const char *str);
- 参数:
str是指向以'\0'结尾的字符串的指针。 - 返回值:返回字符串的长度,不包括结尾的空字符
'\0',返回类型是size_t,这是一个无符号整数类型。
示例代码
#include <stdio.h>
#include <string.h> // 必须包含这个头文件
int main() {
char str1[] = "Hello, World!";
char str2[] = "C Programming";
char str3[] = ""; // 空字符串
// 计算并打印字符串长度
printf("The length of '%s' is %zu\n", str1, strlen(str1)); // 输出: 13
printf("The length of '%s' is %zu\n", str2, strlen(str2)); // 输出: 14
printf("The length of '%s' is %zu\n", str3, strlen(str3)); // 输出: 0
return 0;
}
注意:使用 %zu 来打印 size_t 类型的变量,这是正确的格式说明符。
strlen() 的工作原理
strlen() 内部实现非常简单,它本质上是一个循环,从头开始遍历字符串,直到遇到空字符 '\0' 为止,并计数。

(图片来源网络,侵删)
// strlen() 的一种可能实现(简化版)
size_t my_strlen(const char *str) {
size_t length = 0;
while (*str != '\0') { // 当指针指向的字符不是空字符时
length++;
str++; // 指针移动到下一个字符
}
return length;
}
手动实现字符串长度计算
为了更好地理解原理,或者在某些极端情况下(嵌入式系统不允许使用标准库),你可以自己编写一个函数来计算字符串长度。
使用指针算术
#include <stdio.h>
size_t my_strlen(const char *s) {
const char *p = s; // 保存起始地址
while (*p != '\0') {
p++;
}
return p - s; // 用结束地址减去起始地址,得到字符个数
}
int main() {
char text[] = "Manual Length";
printf("Length: %zu\n", my_strlen(text)); // 输出: 14
return 0;
}
使用数组下标
#include <stdio.h>
size_t my_strlen_array(const char s[]) {
size_t i = 0;
while (s[i] != '\0') { // s[i] 等价于 *(s + i)
i++;
}
return i;
}
int main() {
char text[] = "Array Method";
printf("Length: %zu\n", my_strlen_array(text)); // 输出: 11
return 0;
}
重要注意事项和常见错误
忘记包含 <string.h> 头文件
如果你使用 strlen() 却忘记 #include <string.h>,编译器会报错,提示 strlen 未声明。
误判 strlen() 的返回类型
strlen() 返回的是 size_t,它是一个无符号类型,如果你用一个有符号的 int 变量去接收它,在某些情况下可能会导致警告或逻辑错误。
// 潜在问题
int len = strlen("hello"); // 可能会有警告,因为 int 和 size_t 类型不匹配
// 更好的做法
size_t len = strlen("hello");
最大的危险:缓冲区溢出
strlen() 不会检查字符串的有效性,它会一直向后查找 '\0',如果传入的字符数组不是一个合法的C字符串(即没有 '\0' ,程序会继续读取内存中的随机数据,直到偶然找到一个值为0的字节,或者访问到非法内存导致程序崩溃(段错误)。

(图片来源网络,侵删)
示例:
#include <stdio.h>
#include <string.h>
int main() {
char not_a_string[5] = {'H', 'e', 'l', 'l', 'o'}; // 没有结尾的 '\0'
// 这是危险的!strlen() 会一直读下去,直到找到内存中的第一个 0
size_t len = strlen(not_a_string); // 未定义行为
printf("Length: %zu\n", len); // 输出是不可预测的
return 0;
}
如何避免?
- 确保所有你传递给
strlen()的字符数组都以'\0'- 在定义字符数组时,确保空间足够存放
'\0'。char str[6] = "Hello";// 正确,'H','e','l','l','o','\0'char str[5] = "Hello";// 错误,会导致缓冲区溢出
- 在定义字符数组时,确保空间足够存放
相关概念:sizeof vs strlen()
初学者很容易混淆 sizeof 运算符和 strlen() 函数,它们有本质区别:
| 特性 | sizeof (运算符) |
strlen() (函数) |
|---|---|---|
| 类型 | 运算符,编译时计算 | 函数,运行时计算 |
| 作用对象 | 计算类型或变量所占的内存字节数 | 计算字符串的字符个数 |
是否包含 '\0' |
对于字符数组,包含 '\0' 所占的空间 |
不包含结尾的 '\0' |
| 参数 | sizeof(类型) 或 sizeof 变量 |
strlen(字符串指针) |
示例对比
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello"; // 在内存中是 {'H','e','l','l','o','\0'}
// sizeof 计算整个数组占用的空间
printf("sizeof(str): %zu\n", sizeof(str)); // 输出: 6 (5个字符 + 1个'\0')
// strlen 计算到'\0'之前的字符个数
printf("strlen(str): %zu\n", strlen(str)); // 输出: 5
char *ptr = "Hello"; // ptr 是一个指向字符串字面量的指针
// sizeof(ptr) 计算的是指针变量本身的大小,不是指向内容的大小
printf("sizeof(ptr): %zu\n", sizeof(ptr)); // 在64位系统上通常输出 8
// strlen 仍然计算字符串的长度
printf("strlen(ptr): %zu\n", strlen(ptr)); // 输出: 5
return 0;
}
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
strlen() |
简单、高效、标准、可读性高 | 需要包含头文件,有缓冲区溢出风险 | 绝大多数情况下的首选 |
| 手动实现 | 无需头文件,有助于理解原理 | 代码冗余,不如标准函数高效 | 学习目的、特殊环境(如嵌入式)、面试 |
核心要点:
- 优先使用标准库函数
strlen()。 strlen()返回的是size_t类型。- 绝对要确保传递给
strlen()的字符串是合法的(以'\0',否则会导致未定义行为。 - 清晰区分
sizeof和strlen的不同用途。
