C语言学习10-sizeof和strlen的区别

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,数长度,运行时候才计算

使用建议:

  1. 内存操作用sizeof
  2. 字符串处理用strlen
  3. 数组传参要注意sizeof退化
  4. 内存分配记得给\0留空间
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容