sizeof与strlen有何本质区别?

99ANYc3cd6
预计阅读时长 16 分钟
位置: 首页 C语言 正文
  1. 核心定义
  2. 语法和参数
  3. 工作原理和时机
  4. 返回值
  5. 代码示例
  6. 一张图看懂区别
  7. 总结与关键点

核心定义

  • sizeof: 一个操作符 (Operator),不是函数,它用于计算数据类型或变量在内存中所占用的字节数,它是在编译时就确定的值。
  • strlen: 一个库函数,定义在 <string.h> 头文件中,它用于计算字符串的长度,即字符串中第一个 \0 (空字符) 之前出现的字符个数,它是在运行时计算的。

语法和参数

特性 sizeof strlen
类型 操作符 函数
头文件 无需任何头文件 需要包含 <string.h>
语法 sizeof(类型或变量) strlen(const char *str)
参数 类型名 (如 int, char) 或变量 (如 a, arr) 必须是一个以 \0 结尾的字符串指针

工作原理和时机

这是两者最根本的区别。

c语言 sizeof strlen
(图片来源网络,侵删)

sizeof 的工作原理

sizeof 在编译阶段由编译器处理,它查看变量的类型或类型本身,然后根据目标平台的内存布局规则计算出其大小。

  • 对于变量sizeof 返回该变量类型所占的字节数。
  • 对于数组名sizeof 返回整个数组在内存中占用的总字节数,而不是指针的大小,这是 sizeofstrlen 最常见的“陷阱”所在。

strlen 的工作原理

strlen 在程序运行时执行,它接收一个字符指针,然后从这个指针指向的内存地址开始,一个字节一个字节地向后遍历,直到它遇到第一个值为 \0 的空字符为止,它返回已经遍历过的字符个数。

注意strlen 没有找到 \0,它会一直向后读,直到访问到非法内存,导致程序崩溃(段错误)


返回值

特性 sizeof strlen
返回值类型 size_t (一个无符号整型) size_t (一个无符号整型)
返回值含义 内存占用的字节数 字符串的字符个数
单位 字节 字符

重要提醒:因为 strlen 返回的是 size_t(无符号类型),所以下面这种代码是错误的,会产生意想不到的结果:

c语言 sizeof strlen
(图片来源网络,侵删)
if (strlen("hello") - 5 < 0) { // 错误!
    // ...
}
// "hello"的长度是5, 5-5=0, 0<0为false。
// 但如果换成 strlen("hi") - 5, 2-5=-3,由于是无符号数,-3会变成一个很大的正数,条件永远为true。

代码示例

示例 1:基本用法

#include <stdio.h>
#include <string.h> // 必须包含 strlen 的头文件
int main() {
    char c = 'A';
    char str[] = "Hello"; // 字符串 "Hello\0"
    // --- sizeof ---
    printf("sizeof(char) = %zu\n", sizeof(char));        // 输出: sizeof(char) = 1
    printf("sizeof(c) = %zu\n", sizeof(c));              // 输出: sizeof(c) = 1
    printf("sizeof(str) = %zu\n", sizeof(str));          // 输出: sizeof(str) = 6 (H,e,l,l,o,\0)
    printf("sizeof(\"Hello\") = %zu\n", sizeof("Hello")); // 输出: sizeof("Hello") = 6
    // --- strlen ---
    printf("strlen(str) = %zu\n", strlen(str));          // 输出: strlen(str) = 5 (不计算\0)
    printf("strlen(\"Hello\") = %zu\n", strlen("Hello")); // 输出: strlen("Hello") = 5
    return 0;
}

示例 2:sizeof vs strlen 在数组上的关键区别

这是面试和实际开发中最容易出错的地方。

#include <stdio.h>
#include <string.h>
int main() {
    char arr[] = "Hello"; // 在栈上分配了一个6字节的数组 ['H','e','l','l','o','\0']
    char *ptr = "Hello";  // ptr 是一个指针,指向只读区中的字符串常量 "Hello"
    // --- sizeof ---
    printf("sizeof(arr) = %zu\n", sizeof(arr)); // 输出: 6 (整个数组的大小)
    printf("sizeof(ptr) = %zu\n", sizeof(ptr)); // 输出: 4 或 8 (取决于系统,是指针变量本身的大小)
    // --- strlen ---
    printf("strlen(arr) = %zu\n", strlen(arr)); // 输出: 5 (从arr指向的位置开始找\0)
    printf("strlen(ptr) = %zu\n", strlen(ptr)); // 输出: 5 (从ptr指向的位置开始找\0)
    return 0;
}

示例 3:strlen 的危险性(未找到 \0

#include <stdio.h>
#include <string.h>
int main() {
    char arr[5] = {'H', 'e', 'l', 'l', 'o'}; // 注意:这个数组没有以 '\0' 
    // sizeof 依然安全,因为它只关心分配了多少空间
    printf("sizeof(arr) = %zu\n", sizeof(arr)); // 输出: 5
    // strlen 会发生危险!它会从 'H' 开始读,一直读下去,直到在内存中偶然找到 '\0'
    // 这会导致未定义行为,通常是程序崩溃(段错误)
    // printf("strlen(arr) = %zu\n", strlen(arr)); // <--- 危险!不要运行这行!
    return 0;
}

一张图看懂区别

假设我们有 char str[] = "Hi";,它在内存中是这样分布的:

内存地址 (示例)    +----+----+----+
                   | 'H'| 'i'| '\0'|
                   +----+----+----+
                     ^         ^
                     |         |
               str[0]       str[2] (str[2] == '\0')
                     |
                 str (数组名,代表首元素地址)
  • sizeof(str)

    • 问编译器:“这个叫 str 的数组占多少空间?”
    • 编译器回答:“'H'占1字节,'i'占1字节,'\0'占1字节,总共 3字节。”
    • 结果:3
  • strlen(str)

    c语言 sizeof strlen
    (图片来源网络,侵删)
    • 问程序:“从 str 指向的地址开始,有几个字符,直到遇到 '\0'?”
    • 程序运行时,从地址 'H' 开始数:'H' (1), 'i' (2),下一个是 '\0',停止。
    • 结果:2

总结与关键点

特性 sizeof strlen
本质 编译时操作符 运行时函数
作用 计算内存字节数 计算字符串字符数
参数 类型/变量 必须是以 \0 结尾的字符串
安全性 总是安全 不安全,若字符串未以 \0 结尾会越界访问
对数组名 返回整个数组的大小 返回字符串的长度
对指针 返回指针本身的大小 返回指针指向的字符串的长度

如何记忆?

  • sizeof -> Size of Memory -> 内存大小 -> 计算字节数。
  • strlen -> String Length -> 字符串长度 -> 计算字符数。

黄金法则: 当你想知道一个变量或类型占多少内存时,用 sizeof。 当你想知道一个以 \0 结尾的字符串有多长时,用 strlen

-- 展开阅读全文 --
头像
C语言int与double转换会丢失精度吗?
« 上一篇 12-12
kindeditor dede插件如何安装使用?
下一篇 » 12-12

相关文章

取消
微信二维码
支付宝二维码

目录[+]