sizeof和strlen详细讲解

本文详细比较了sizeof和strlen在计算内存占用和字符串长度方面的差异,通过示例展示了如何在不同数据结构(如一维数组、二维数组和指针)中运用,并强调了它们对内存地址和0字符的处理
摘要由CSDN通过智能技术生成

一.sizeof和strlen的区别对比

sizeof:1.sizeof是单目操作符。

             2.计算操作数所占内存的大小,单位是字节。

             3.不关注内存中存放什么数据。

strlen:1.是库函数,使用时需要包括头文件string.h。

            2.是求字符串长度的,统计的是\0之前的个数。

            3.关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界。

注意:如果sizeof里面有表达式,这个表达式是不参与计算的。

二.用一维数组理解sizeof和strlen

先给大家看两组代码,大家可以先尝试计算一下。

想计算这些,我们需要首先知道这里的arr所代表的是什么?关于数组名,只有两种情况代表的是整个数组。1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节

2. &数组名 - 数组名表示整个数组,取出的是整个数组的地址

只有这两种情况代表的是整个数组,其他的都是代表首元素的地址

我把源码放在这里,大家可以自行打印看一下,不懂的一定要看一下里面的注释。

#include <stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", sizeof(arr));              //数组名单独放在sizeof内部了,计算的是数组的大小,单位是字节6
	printf("%d\n", sizeof(arr + 0));          //这里的arr并没有符合上面我说的两个条件,arr并没有单独放在sizeof里面,也没有用&,所以arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*arr));             //arr是首元素的地址,*arr就是首元素,大小就是1个字节
	                                          //*arr -- arr[0] - *(arr+0)
	printf("%d\n", sizeof(arr[1]));           //arr[1] 是第二个元素,大小也是1个字节
	printf("%d\n", sizeof(&arr));             //&arr 是数组地址,数组的地址也是地址,大小是4/8个字节
	                                          //&arr -- char (*)[6]
	printf("%d\n", sizeof(&arr + 1)) ;        //&arr+1, 跳过整个数组,指向了数组后边的空间,4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));      //第二个元素的地址,是地址就是4/8字节

	return 0;
}

这里的4或8个字节取决于你的编译器是x86环境还是x64环境。

这里我把这串代码所有的sizeof都换成strlen大家再来想一想结果是多少?

可以先思考一下再看注释。

#include <stdio.h>
#include <string.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));  //arr是首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的
	printf("%d\n", strlen(arr + 0));//arr+0是数组首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的
	printf("%d\n", strlen(*arr));   //arr是首元素的地址,*arr是首元素,就是'a','a'的ascii码值是97
 //就相当于把97作为地址传递给了strlen,strlen得到的就是野指针, 代码是有问题的
	printf("%d\n", strlen(arr[1]));  //arr[1]--'b'--98,传给strlen函数也是错误的
	printf("%d\n", strlen(&arr)); //&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值 x
	printf("%d\n", strlen(&arr + 1)); //随机值 x-6
	printf("%d\n", strlen(&arr[0] + 1)); //从第2个元素开始向后统计的,得到的也是随机值 x-1

	return 0;
}

大家一定要注意一下printf("%d\n", strlen(arr[1]))和printf("%d\n", strlen(*arr))这两个代码虽然长的人模狗样的,但都是错误的代码,大家运行的时候一定要把这两个代码注释掉

三.用指针再探sizeof和strlen

这里我们声明一个char *类型的指针p,先来看sizeof的运算。

#include <stdio.h>

int main()
{
	const char * p = "abcdef";

	printf("%d\n", sizeof(p)); //p是指针变量,我们计算的是指针变量的大小,4/8个字节
	printf("%d\n", sizeof(p + 1)); //p + 1是b的地址,是地址大小就是4/8个字节
	printf("%d\n", sizeof(*p));   //p的类型是const char*, *p就是char类型了,1个字节
	printf("%d\n", sizeof(p[0])); //1. p[0] --> *(p+0)--> *p --> 'a',大小是1字节
	                              //2. 把常量字符串想象成数组,p可以理解为数组名,p[0], 就是首元素

	printf("%d\n", sizeof(&p)); //取出的是p的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&p + 1));  //&p + 1是跳过p指针变量后的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&p[0] + 1));//4/8 &p[0]-取出字符串首字符的地址,+1是第二个字符的地址,大小是4/8个字节

	return 0;
}

这里有个地方我想单独说一下,就是关于&p的理解,大家不要把&p理解成abcdef的地址了,我们已经把abcdef的地址给了p,我们再用&p取的是变量p的地址不再是abcdef的地址了,简单的说,这里的&p与abcdef关系不大了。而再加一后跳过去了整个指针变量p,咱们计算的是个地址,所以就是4或者8。

咱们再来看一看把sizeof换成strlen。

#include <stdio.h>
#include <string.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	printf("%d\n", strlen(*p));//*p就是'a'-97,err
	printf("%d\n", strlen(p[0]));//p[0]--> *(p+0)--> *p //err
	printf("%d\n", strlen(&p));//&p是指针变量p的地址,和字符串"abcdef"关系就不大了
	//从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值
	printf("%d\n", strlen(&p + 1));//随机值

	printf("%d\n", strlen(&p[0] + 1));//&p[0]-取出字符串首字符的地址,+1是第二个字符的地址, 5

	return 0;
}

 

如图,&p加一之后相当于把自己给跳过去了。大家可以额外思考一下这里的strlen(&p)和strlen(&p+1)这里的两个数值有什么关系。实际上没有什么关系。如图下:

strlen只要遇到\0就不走了,所以真正的关系我们不知道。

四.用二维数组再探sizeof

#include <stdio.h>
#include <string.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));       //a是数组名,单独放在sizeof内部,计算的是数组的大小,单位是字节 - 48 = 3*4*sizeof(int)
	printf("%d\n", sizeof(a[0][0])); //a[0][0] 是第一行第一个元素,大小4个字节 
	printf("%d\n", sizeof(a[0]));    //a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节
	printf("%d\n", sizeof(a[0] + 1));//a[0]第一行的数组名,但是a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是
	                                 //数组首元素的地址,就是&a[0][0],+1后是a[0][1]的地址,大小是4/8个字节

	printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示第一行第二个元素,大小就是4
	printf("%d\n", sizeof(a + 1));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
	//第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节

	printf("%d\n", sizeof(*(a + 1)));//1.a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小 - 16
	//2. *(a + 1) == a[1], a[1]是第二行的数组名,sizeof(*(a + 1))就相当于sizeof(a[1]),意思是把第二行的数组名单独放在
	//sizeof内部,计算的是第二行的大小
	printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的就是数组的地址,就是第一行的地址
	//&a[0]+1 就是第二行的地址,是地址大小就是4/8个字节
	printf("%d\n", sizeof(*(&a[0] + 1)));//*(&a[0] + 1)意思是对第二行的地址解引用,访问的就是第二行,大小是16字节
	printf("%d\n", sizeof(*a));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
	//第一行的地址,*a就是第一行,计算的就是第一行的大小,16字节
	//*a == *(a+0) == a[0]
	printf("%d\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度
	//a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16个字节
	return 0;
}

由于我没有写关于数组的博客,关于二维数组的我画个图让大家更更清晰明了的看到。

用鼠标画的,别介意。

虽然是个二维数组,但在内存里的排序方式还是和一维数组大差不差的,都是连续存放的。

关于这一篇的博客,非常感谢我的老师鹏哥,如果我有理解的不对的地方,请大家多多指正。感谢。

  • 28
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值