C++ sizeof 和 strlen 的区别?
在 C++(以及 C 语言)中,sizeof 和 strlen 是两个经常被放在一起比较的概念,尤其是在处理字符串和数组时。它们虽然常常用于获取“长度”或“大小”,但其本质、工作原理和应用场景完全不同。
以下是它们的核心区别总结:
1. 核心对比速览
| 特性 | sizeof |
strlen |
|---|---|---|
| 本质 | 单目运算符 (Operator) | 库函数 (Function) |
| 计算时机 | 编译时(绝大多数情况) | 运行时 |
| 功能 | 计算数据类型或变量所占的内存字节数 | 计算 C 风格字符串的字符长度 |
| 参数类型 | 任何数据类型、变量、对象、数组等 | 必须是以 \0 结尾的字符指针 (const char*) |
对 \0 的处理 |
包含 \0 的空间(如果是字符数组) |
不包含 \0,遇到 \0 即停止计算 |
| 所属头文件 | 属于 C++ 核心语法,不需要头文件 | 需要引入 <cstring> 或 <string.h> |
2. 详细解析与代码示例
(1) sizeof:内存的“测量尺”
sizeof 关心的是在内存中分配了多少空间。因为它通常在编译时计算,所以它不会去读取变量里面的具体内容。
cpp
char arr[100] = "hello";
cout << sizeof(arr); // 输出 100。因为数组声明了 100 个字节的空间。
char str[] = "hello";
cout << sizeof(str); // 输出 6。因为 "hello" 有 5 个字母,加上隐藏的结束符 '\0',共占用 6 个字节。
int num = 10;
cout << sizeof(num); // 输出 4(在大多数 32/64 位系统上,int 占 4 字节)。
(2) strlen:字符串的“计步器”
strlen 关心的是字符串里有多少个有效字符。它的工作原理是从给定的内存地址开始往后遍历,直到遇到第一个 \0(ASCII 码为 0 的字符)才停止,并返回遍历经过的字符个数。
cpp
#include <cstring>
char arr[100] = "hello";
cout << strlen(arr); // 输出 5。它只数到 'o',遇到 '\0' 就停了,不管数组实际有多大。
char str[] = "hello";
cout << strlen(str); // 输出 5。同样不包含 '\0'。
char badStr[5] = {'h', 'e', 'l', 'l', 'o'}; // 注意:这里没有空间放 '\0'
// cout << strlen(badStr); // 危险操作!它会越界读取,直到在内存其他地方碰巧遇到 '\0',返回一个不可预知的垃圾值。
3. 最容易踩坑的场景:数组退化为指针
这是面试中最常考的陷阱。当把数组名赋给指针,或者将数组作为参数传递给函数时,数组会“退化”为指针。
cpp
char str[] = "hello";
char* ptr = str;
// sizeof 的区别
cout << sizeof(str); // 输出 6(计算整个字符数组的大小)
cout << sizeof(ptr); // 输出 8 或 4(计算指针变量本身的大小,64位系统为8字节,32位系统为4字节)
// strlen 的表现一致
cout << strlen(str); // 输出 5
cout << strlen(ptr); // 输出 5
函数参数传值的陷阱:
cpp
void test(char arr[]) {
// 这里的 arr 看似是数组,其实已经被编译器隐式转换为了指针 char*
cout << sizeof(arr) << endl; // 输出 8 (或4),而不是数组原本的大小!
cout << strlen(arr) << endl; // 输出字符串的实际长度
}
int main() {
char str[100] = "hello";
test(str);
return 0;
}
4. 总结与现代 C++ 建议
- 用
sizeof:当你需要知道一个类型、结构体、类或静态数组在内存中占用多少字节时(例如在调用memset、memcpy或进行底层内存分配时)。 - 用
strlen:当你处理 C 风格字符串(char*),并且需要知道它包含多少个可见字符时。
🌟 现代 C++ 最佳实践:
在现代 C++ 中,强烈建议尽量减少 C 风格字符串(char* 和 strlen)的使用,转而使用:
std::string:直接使用str.length()或str.size()获取长度,安全且高效。std::size()(C++17):用于安全地获取数组的元素个数,如果传入退化的指针会在编译时报错,避免了sizeof计算数组长度时的潜在 Bug。std::string_view(C++17):用于替代只读的const char*,自带长度信息,无需像strlen那样每次遍历计算。
右滑查看面试常问