sizeof 和 strlen的理解与区分

引入:

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 intunsigned 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

相关推荐
m0_743106462 小时前
【浙大&南洋理工最新综述】Feed-Forward 3D Scene Modeling(五)
人工智能·算法·计算机视觉·3d·几何学
Chockong3 小时前
11_vim自动插入文件头模板(.c/.cpp/.py/.txt)设置
c语言·vim
学会去珍惜10 小时前
是什么意思c语言
c语言·编程语言·底层开发·面向过程·系统软件
kobesdu11 小时前
人形机器人SLAM:技术挑战、算法综述与开源方案
算法·机器人·人形机器人
handler0112 小时前
拒绝权限报错!三分钟掌握 Linux 权限管理
linux·c语言·c++·笔记·学习
椰羊~王小美12 小时前
随机数概念及算法
算法
阿Y加油吧13 小时前
算法实战笔记:LeetCode 169 多数元素 & 75 颜色分类
笔记·算法·leetcode
不要秃头的小孩13 小时前
力扣刷题——509. 斐波那契数
python·算法·leetcode·动态规划