sizeof和strlen的区别
引言
在C/C++编程中,strlen和sizeof是两个常用但经常被混淆的操作。它们虽然看起来功能相似,但实际上有着本质区别。本文将从多个角度深入剖析这两者的差异,帮助读者彻底理解并在面试中正确应对相关问题。
二者的基本定义与功能
strlen
strlen是一个函数,定义在<string.h>(C)或<cstring>(C++)头文件中。其原型为:
size_t strlen(const char *str);
它计算字符串的长度,即从字符串首地址开始直到遇到第一个空字符'\0'之前的字符个数。
sizeof
sizeof是一个运算符,而非函数。其基本形式为:
sizeof(type)
sizeof expression
它返回操作数的字节大小,可以应用于任何数据类型或表达式。
本质区别
计算方式:
- strlen:运行时计算,需要遍历字符串直到找到'\0'
- sizeof:编译时确定,是静态计算
返回值含义:
- strlen:返回字符数量(不包括结尾的'\0')
- sizeof:返回占用的内存字节数
适用对象:
- strlen:只能用于以'\0'结尾的字符串
- sizeof:可用于任何数据类型或变量
典型示例分析
示例1:字符数组
在C语言中,字符串末尾会自动添加\0作为结束标志
char str[10] = "hello";
printf("strlen(str) = %zu\n", strlen(str)); // 输出:5
printf("sizeof(str) = %zu\n", sizeof(str)); // 输出:10
%zu 是C语言中的格式说明符,用于 printf() 函数中打印 size_t 类型的值。
解析:
- strlen(str)计算字符串"hello"的长度,为5个字符
- sizeof(str)计算整个数组的大小,为10字节
示例2:字符指针
char *ptr = "hello";
printf("strlen(ptr) = %zu\n", strlen(ptr)); // 输出:5
printf("sizeof(ptr) = %zu\n", sizeof(ptr)); // 输出:4或8(取决于系统)
解析:
- strlen(ptr)计算字符串"hello"的长度,为5
- sizeof(ptr)计算指针变量本身的大小,在32位系统上为4字节,在64位系统上为8字节
示例3:包含空字符的数组
char str[] = {'h', 'e', 'l', 'l', 'o', '\0', 'x', 'y', 'z'};
printf("strlen(str) = %zu\n", strlen(str)); // 输出:5
printf("sizeof(str) = %zu\n", sizeof(str)); // 输出:9
解析:
- strlen遇到第一个'\0'就停止计数
- sizeof计算整个数组的大小,包括'\0'后面的字符
示例4:不包含空字符的数组
char str[] = {'h', 'e', 'l', 'l', 'o', 'x', 'y', 'z'};
printf("strlen(str) = %zu\n", strlen(str)); // 输出:随机值
printf("sizeof(str) = %zu\n", sizeof(str)); // 输出:8
解析:
- 在C语言中,字符串末尾会自动添加\0作为结束标志,但是字符的末尾没有\0作为结束的标志
没有\0,当使用strlen函数进行计算是就不知道在哪里结束;计算结果就是我们想不到的随机值(比如运行结果14028835)意思是当使用strlen函数进行计算时,当计算完arr数组时,因为没遇到\0,所以还要继续往后计算,(这里直到计算了14028835个字符后)才遇到\0结束
性能考量
执行效率:
- sizeof:编译时确定,执行时无开销
- strlen:需要遍历整个字符串,时间复杂度为O(n)
安全性:
- sizeof:不会导致缓冲区溢出
- strlen:如果字符串没有'\0'结尾,可能导致越界访问
常见面试陷阱
陷阱1:宏定义字符串
#define TEXT "Hello"
printf("%zu\n", sizeof(TEXT)); // 输出:6
printf("%zu\n", strlen(TEXT)); // 输出:5
解析:sizeof(TEXT)包含了结尾的'\0',而strlen(TEXT)不包含。
陷阱2:多维数组
char matrix[3][4] = {"abc", "de", "f"};
printf("%zu\n", sizeof(matrix)); // 输出:12
printf("%zu\n", strlen(matrix[0])); // 输出:3
printf("%zu\n", strlen(matrix[1])); // 输出:2
printf("%zu\n", strlen(matrix[2])); // 输出:1
解析:sizeof(matrix)计算整个二维数组的大小,而strlen计算每行字符串的长度。
陷阱3:非字符串类型
int numbers[5] = {1, 2, 3, 4, 5};
printf("%zu\n", sizeof(numbers)); // 输出:20(5*4字节)
printf("%zu\n", strlen(numbers)); // 编译警告,行为未定义
解析:strlen只能用于字符串,用于其他类型会导致未定义行为。
实际应用场景
使用sizeof的场景
动态内存分配
int *arr = (int*)malloc(10 * sizeof(int));
计算数组元素个数
int arr[] = {1, 2, 3, 4, 5};int count = sizeof(arr) / sizeof(arr[0]); // 计算数组元素个数
结构体大小计算:
struct Person {char name[50];int age;};size_t size = sizeof(struct Person);
使用strlen的场景
字符串操作:
char str[100] = "Hello";strcat(str, " World"); // 连接字符串size_t new_length = strlen(str); // 计算新字符串长度
内存分配:
char *src = "Hello";char *dst = (char*)malloc(strlen(src) + 1); // +1 为结尾的'\0'strcpy(dst, src);
字符串验证:
if (strlen(password) < 8) {printf("密码太短!\n");}
总结
理解strlen和sizeof的区别对于C/C++程序员至关重要:
本质不同:strlen是函数,sizeof是运算符
计算时机:strlen运行时计算,sizeof编译时确定
返回含义:strlen返回字符数,sizeof返回字节数
适用范围:strlen仅适用于字符串,sizeof适用于任何类型