1. 基本概念对比
| 特性 | sizeof | strlen |
|---|---|---|
| 本质 | 操作符(operator) | 库函数(library function) |
| 头文件 | 不需要 | #include <string.h> |
| 参数 | 数据类型或变量 | 只能是以\0结尾的字符串 |
| 计算时机 | 编译时 | 运行时 |
| 返回值含义 | 数据类型占内存的大小(字节) | 字符串的实际长度(不含\0) |
2. 基础用法示例
#include <stdio.h>
#include <string.h>
int main() {
// ========== sizeof 示例 ==========
printf("=== sizeof 操作符示例 ===\n");
// 对数据类型使用sizeof
printf("sizeof(int) = %zu\n", sizeof(int));
printf("sizeof(double) = %zu\n", sizeof(double));
printf("sizeof(char) = %zu\n", sizeof(char));
// 对变量使用sizeof
int num = 100;
char ch = 'A';
double d = 3.14;
printf("sizeof(num) = %zu\n", sizeof(num));
printf("sizeof(ch) = %zu\n", sizeof(ch));
printf("sizeof(d) = %zu\n", sizeof(d));
// ========== strlen 示例 ==========
printf("\n=== strlen 函数示例 ===\n");
char str1[] = "Hello";
char str2[] = "World!";
char *str3 = "C Programming";
printf("strlen(\"Hello\") = %zu\n", strlen("Hello"));
printf("strlen(str1) = %zu\n", strlen(str1));
printf("strlen(str2) = %zu\n", strlen(str2));
printf("strlen(str3) = %zu\n", strlen(str3));
return 0;
}
运行结果:
=== sizeof 操作符示例 ===
sizeof(int) = 4
sizeof(double) = 8
sizeof(char) = 1
sizeof(num) = 4
sizeof(ch) = 1
sizeof(d) = 8
=== strlen 函数示例 ===
strlen("Hello") = 5
strlen(str1) = 5
strlen(str2) = 6
strlen(str3) = 13
3. 数组处理的重要区别
数组作为参数时的行为差异
#include <stdio.h>
#include <string.h>
void test_array(char arr[]) {
printf("在函数内部:\n");
printf("sizeof(arr) = %zu (退化为指针大小)\n", sizeof(arr));
printf("strlen(arr) = %zu\n", strlen(arr));
}
int main() {
char str[] = "Hello World";
printf("在main函数中:\n");
printf("sizeof(str) = %zu (整个数组大小)\n", sizeof(str));
printf("strlen(str) = %zu\n", strlen(str));
printf("\n字符串内容:%s\n", str);
printf("数组长度:%zu\n", sizeof(str)); // 包含\0
printf("字符串长度:%zu\n", strlen(str)); // 不包含\0
// 传递给函数
test_array(str);
return 0;
}
运行结果:
在main函数中:
sizeof(str) = 12 (整个数组大小)
strlen(str) = 11
字符串内容:Hello World
数组长度:12
字符串长度:11
在函数内部:
sizeof(arr) = 8 (退化为指针大小)
strlen(arr) = 11
4. 字符串处理的关键差异
包含\0的字符串处理
#include <stdio.h>
#include <string.h>
int main() {
// 情况1:正常字符串
char normal_str[] = "Hello";
printf("正常字符串: \"%s\"\n", normal_str);
printf("sizeof = %zu, strlen = %zu\n\n", sizeof(normal_str), strlen(normal_str));
// 情况2:包含空字符的字符串
char with_null[] = "Hello\0World";
printf("包含空字符的字符串\n");
printf("字符串内容: ");
for(int i = 0; i < sizeof(with_null); i++) {
if(with_null[i] == '\0')
printf("\\0");
else
printf("%c", with_null[i]);
}
printf("\n");
printf("sizeof = %zu (包含所有字符和\\0)\n", sizeof(with_null));
printf("strlen = %zu (遇到第一个\\0停止)\n\n", strlen(with_null));
// 情况3:字符数组
char char_array[] = {'H', 'e', 'l', 'l', 'o'}; // 没有\0结尾
printf("字符数组(没有\\0结尾):\n");
printf("sizeof = %zu\n", sizeof(char_array));
printf("strlen = %zu (未定义行为,可能继续读取直到遇到\\0)\n", strlen(char_array));
return 0;
}
运行结果:
正常字符串: "Hello"
sizeof = 6, strlen = 5
包含空字符的字符串
字符串内容: Hello\0World
sizeof = 12 (包含所有字符和\0)
strlen = 5 (遇到第一个\0停止)
字符数组(没有\0结尾):
sizeof = 5
strlen = 5 (未定义行为,可能继续读取直到遇到\0)
5. 编译时vs运行时计算
验证计算时机差异
#include <stdio.h>
#include <string.h>
#include <time.h>
// 动态生成字符串的函数
char* generate_string() {
static char buffer[100];
printf("生成字符串中...\n");
strcpy(buffer, "Dynamic String");
return buffer;
}
int main() {
printf("=== 计算时机验证 ===\n");
// sizeof在编译时计算
printf("1. sizeof在编译时确定:\n");
printf(" sizeof(int[100]) = %zu\n", sizeof(int[100]));
printf(" sizeof(\"Hello\") = %zu\n\n", sizeof("Hello"));
// strlen在运行时计算
printf("2. strlen在运行时计算:\n");
clock_t start, end;
start = clock();
size_t len = strlen(generate_string());
end = clock();
printf(" 字符串长度: %zu\n", len);
printf(" 计算耗时: %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
运行结果:
=== 计算时机验证 ===
1. sizeof在编译时确定:
sizeof(int[100]) = 400
sizeof("Hello") = 6
2. strlen在运行时计算:
生成字符串中...
字符串长度: 14
计算耗时: 0.000012秒
6. 实际应用场景对比
内存分配和字符串操作
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
printf("=== 实际应用场景 ===\n");
// 场景1:内存分配
char source[] = "This is a test string";
// 错误的做法:使用strlen分配内存(会少1个字节给\0)
// char *dest1 = (char*)malloc(strlen(source)); // 错误!
// 正确的做法:使用sizeof或strlen+1
char *dest2 = (char*)malloc(sizeof(source)); // 方法1:使用sizeof
char *dest3 = (char*)malloc(strlen(source) + 1); // 方法2:使用strlen+1
strcpy(dest2, source);
strcpy(dest3, source);
printf("源字符串: %s\n", source);
printf("使用sizeof分配: %s (大小: %zu)\n", dest2, sizeof(source));
printf("使用strlen+1分配: %s (长度: %zu)\n", dest3, strlen(source));
free(dest2);
free(dest3);
// 场景2:数组遍历
printf("\n=== 数组遍历示例 ===\n");
int numbers[] = {1, 2, 3, 4, 5};
int count = sizeof(numbers) / sizeof(numbers[0]); // 计算元素个数
printf("数组元素个数: %d\n", count);
printf("遍历数组: ");
for(int i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
运行结果:
=== 实际应用场景 ===
源字符串: This is a test string
使用sizeof分配: This is a test string (大小: 22)
使用strlen+1分配: This is a test string (长度: 21)
=== 数组遍历示例 ===
数组元素个数: 5
遍历数组: 1 2 3 4 5
7. 常见错误和陷阱
容易混淆的情况
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 常见陷阱示例 ===\n");
// 陷阱1:指针vs数组
char str_array[] = "Hello";
char *str_pointer = "Hello";
printf("char str_array[] = \"Hello\";\n");
printf("char *str_pointer = \"Hello\";\n\n");
printf("sizeof(str_array) = %zu (数组大小)\n", sizeof(str_array));
printf("sizeof(str_pointer) = %zu (指针大小)\n", sizeof(str_pointer));
printf("strlen(str_array) = %zu\n", strlen(str_array));
printf("strlen(str_pointer) = %zu\n\n", strlen(str_pointer));
// 陷阱2:字符串字面量
printf("字符串字面量:\n");
printf("sizeof(\"Hello\") = %zu (包含\\0)\n", sizeof("Hello"));
printf("strlen(\"Hello\") = %zu (不包含\\0)\n\n", strlen("Hello"));
// 陷阱3:结构体中的差异
struct Test {
char name[20];
char *title;
};
printf("结构体大小分析:\n");
printf("sizeof(struct Test) = %zu\n", sizeof(struct Test));
printf("其中name数组占20字节,指针占%zu字节\n", sizeof(char*));
return 0;
}
运行结果:
=== 常见陷阱示例 ===
char str_array[] = "Hello";
char *str_pointer = "Hello";
sizeof(str_array) = 6 (数组大小)
sizeof(str_pointer) = 8 (指针大小)
strlen(str_array) = 5
strlen(str_pointer) = 5
字符串字面量:
sizeof("Hello") = 6 (包含\0)
strlen("Hello") = 5 (不包含\0)
结构体大小分析:
sizeof(struct Test) = 28
其中name数组占20字节,指针占8字节
8. 总结记忆技巧
核心区别口诀:
- sizeof:看类型,算大小,编译时期就确定
-
strlen:找
\0,数长度,运行时候才计算
使用建议:
- 内存操作用sizeof
- 字符串处理用strlen
- 数组传参要注意sizeof退化
-
内存分配记得给
\0留空间