引入:
sizeof 和strlen 作为两个很简单但却很容易混淆的知识点,有必要单独拎出来讲讲
一:sizeof
1:概念
sizeof 是 C 语言中的一个操作符(运算符),用于计算数据类型或变量在内存中所占的字节数。
①:操作符意味着不是函数,不是函数就代表sizeof不需要包括头文件就可以直接使用,就好比++
②:返回字节数,就是以字节为单位返回变量的大小
2:语法
cpp
sizeof(类型名) // 对类型名必须加括号
sizeof 表达式 // 对表达式可以不加括号
示例:
cpp
sizeof(int); // ✅ 正确,类型名必须加括号
// sizeof int; // ❌ 错误!对类型名必须加括号
int x = 10;
sizeof(x); // ✅ 正确
sizeof x; // ✅ 正确,表达式可以不加括号
sizeof(&x); // ✅ 指针的大小
3:返回值
sizeof本身的返回值的类型是不确定的,根据不同的编译器或系统平台,可能会被定义为 unsigned int、unsigned long,甚至是 unsigned long long,这样的话,打印的格式就是为 %u、%lu 或 %llu,这种不确定性会降低程序的可移植性------同一个程序在不同平台上可能要用不同的占位符才能正确打印。
为了解决这个问题,C 语言引入了统一的类型别名 size_t,用来代表 sizeof 的返回值类型,并且推荐使用专门为其设计的 %zd 来打印,从而保证代码在不同平台上的兼容性和正确性。
类型不确定 → 占位符不统一 → 可移植性差 → 引入
size_t统一类型 → 用%zd统一打印
4:数组名对于sizeof的例外
我们知道数组名arr一般是表示首元素地址,但其在sizeof中是例外的,sizeof(数组名) --- 计算整个数组的大小(总字节数),不论数组类型是什么,都可以使用sizeof去计算总字节数
5:应用场景
而sizeof的应用场景主要是计算一个数组的大小(总字节数),其可以计算不同类型的数组的大小,但是一般用来计算整形数组的大小(总字节数),去除上第一个整形元素的大小,得到该整形数组的元素个数sz,然后通过sz-1得到最后一个元素的下标
示例:
cpp
#include <stdio.h>
int main() {
int arr[] = { 10, 20, 30, 40, 50 };
// 得到数组的元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
// 最后一个元素的下标
int last_index = sz - 1;
printf("数组总字节数: %d\n", sizeof(arr)); // 假设 int 占 4 字节 → 20
printf("每个元素字节数: %d\n", sizeof(arr[0])); // 4
printf("数组元素个数: %d\n", sz); // 5
printf("最后一个元素下标: %d\n", last_index); // 4
printf("最后一个元素的值: %d\n", arr[last_index]); // 50
return 0;
}
运行结果:

这样的写法,当收到的数组改变的时候,也能够正确去获取到元素个数和末尾元素下标
二:strlen
1:函数原型
strlen是字符串函数,也就是针对于字符串去使用的函数,其一般作用于一个字符串或者是一个字符数组,函数原型如下:
cpp
size_t strlen(const char *s);
头文件 :
#include <string.h>参数:
const char *s:指向以空字符'\0'结尾的字符数组(C风格字符串)的指针
const表示函数不会修改传入的字符串内容返回值:
size_t:无符号整数类型(通常是unsigned int或unsigned long)返回字符串中
'\0'之前的字符个数(不包括'\0'本身)函数功能:
我们知道,字符串都是默认有一个隐式的'\0'作为结尾,当strlen接收到一个char*类型的参数之后,就会一直往后以字节为单位的去读取数据,直接遇到'\0'就停下,返回字符串中
'\0'之前的字符个数(不包括'\0'本身)
而strlen作用于字符数组的时候,接受的参数就是arr数组名,因为数组名就是数组的首元素起始地址,在字符数组中,就是一个char类型的地址,所以就是char*,正好和strlen的参数类型匹配
而当我们通过strlen函数获取到字符串中 '\0' 之前的字符个数(不包括 '\0' 本身)的时候,我们一般会再-1,也就是用strlen(arr)-1 去获取到最后一个元素的下标,方便使用
其次对于返回值和打印格式,strlen没有向sizeof那么严格,必须用 size_t 加上 %zd的组合,你也可以使用int 和 %d,但最正确的方式仍然是 size_t 加上 %zd
2:使用场景
cpp
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = {"Hello"}; // 实际存储: 'H','e','l','l','o','\0'
// 获取字符串长度(不包括 '\0')
int len = strlen(arr); // len = 5
// 最后一个元素的下标
int last_index = len - 1; // last_index = 4
printf("字符串: %s\n", arr); // Hello
printf("字符串长度: %d\n", len); // 5
printf("最后一个元素下标: %d\n", last_index); // 4
printf("最后一个元素: %c\n", arr[last_index]); // o
return 0;
}
运行结果:

3:strlen的参数来源
strlen的作用对象就是字符串或者字符数组,字符数组的数组名就是char*类型的,可以直接作用于strlen的参数去得到整个字符数组的大小(总字节数)
而当作用对象是字符串的时候,有几种写法:
cpp
#include <stdio.h>
int main() {
// ========== 字符串的几种写法 ==========
// 1. 字符串字面量初始化字符数组(最常用)
char str1[] = "Hello"; // 自动分配6字节(含'\0')
// 2. 指定长度的字符串数组
char str2[10] = "Hello"; // 长度10,前6字节"Hello\0",后面补0
// 3. 字符指针指向字符串常量
char *str3 = "Hello"; // 指向只读字符串常量
return 0;
}
**解释:**三种写法本质都是一个道理,只不过第3种只可读,三种写法都可以直接把变量名作为strlen的参数,示例如下:
cpp
#include <stdio.h>
#include <string.h> // strlen 函数需要这个头文件
int main() {
// ========== 字符串的几种写法 ==========
// 1. 字符串字面量初始化字符数组(最常用)
char str1[] = "Hello"; // 自动分配6字节(含'\0')
// 2. 指定长度的字符串数组
char str2[10] = "Hello"; // 长度10,前6字节"Hello\0",后面补0
// 3. 字符指针指向字符串常量
char* str3 = "Hello"; // 指向只读字符串常量
// ========== 三种写法都可以直接作为 strlen 的参数 ==========
int len1 = strlen(str1); // str1 是数组名,退化为指针
int len2 = strlen(str2); // str2 是数组名,退化为指针
int len3 = strlen(str3); // str3 已经是指针
// 打印结果
printf("str1 = \"%s\", 长度 = %d\n", str1, len1); // Hello, 5
printf("str2 = \"%s\", 长度 = %d\n", str2, len2); // Hello, 5
printf("str3 = \"%s\", 长度 = %d\n", str3, len3); // Hello, 5
return 0;
}

唯一需要注意的是:
Q:为什么可以这么写? char *str3 = "Hello";
**A:**这行代码之所以合法,是因为C语言允许字符串字面量隐式转换为指向其首字符的指针,也就是char*类型的str3存储就是字符串 "Hello"的首地址,这就和字符数组的数组名是一个道理
三:二者对比
1:下标的获取
sizeof和strlen一般都是用来获取一个数组的末尾元素的下标,sizeof一般作用于整形数组,strlen一般作用于字符数组!二者获取到元素的个数之后都会再-1去获取到末尾元素的下标!
**①:**strlen只能作用于字符数组,因为其参数是char*,并且本身就叫做字符串函数
**②:**sizeof并不是只能作用于整形数组,其也可以作用于字符数组,但是由于sizeof的特性是返回数组容量,不是实际使用长度,所以一般不使用sizeof去对字符数组进行操作
cpp
// sizeof 返回的是数组容量,不是实际使用长度
char buf[1024] = "Hello";
// 数组容量:1024字节
// 实际字符串:"Hello" 只有5个字符
// sizeof(buf) = 1024 → 错误
// strlen(buf) = 5 → 正确
// ========== 正确的方式:用 strlen ==========
int correct_len = strlen(buf); // 5 ✅
int correct_last_index = strlen(buf) - 1; // 4 ✅
**解释:**也就是说,字符数组使用strlen才是正确完美的;其次sizeof是不会舍弃'\0'的,'\0'占据的字节空间也会被记录在内,所以于情于理其都是不建议去作用于字符数组的
2:数组名在二者中的区别
sizeof(arr)是利用了数组名的例外,去得到了整个数组的大小(总字节数),而strlen(arr),并不是例外,其中的arr就是数组首元素的地址,类型为char*
3:什么时候用谁?
二者在C语言初阶时一般都是用于去求一个数组的末尾元素的下标,当目标是整形数组就用sizeof,而目标是字符数组或者字符串就用strlen