C语言sizeof操作符与strlen函数

1.sizeof与strlen的介绍

(1).sizeof

  • 计算变量的内存空间大小
  • 底层实际上是对变量类型的计算。
  • 是一个单目操作符,不是函数,后面的括号可以省略

(2).strlen 

函数原型
  • strlen是一个函数,返回的size_t类型的数据,头文件为string.h
  • 计算字符串'\0'前的字符个数,计算字符长度
  • 如果没有找到'\0'就继续往下找,通常对于没有'\0'的字符生成的是一个随机值
  • 函数通过首元素的地址往下找。

(3)sizeof与strlen对比 

对比sizeofstrlen
所属类型单目操作符库函数
计算内容

元素的内存空间大小

(单位:字节)

元素的个数
特性

1.括号可有可无

2.只关注变量的类型

3.不关注变量中的数据是啥

1.通过地址往后找

2.找到' \0 '后结束

3.找不到' \0 '一直向后找

2.sizeof和strlen的使用

下面通过使用sizeof和strlen对数组进行操作的例子来加深我们的理解吧

在举例前我们先要知道数组和sizeof(数组名),以及取地址数组名的区别:

对比一维数组的数组名,以arr[10]为例:

对比arrsizeof(arr)&arr
含义数组首元素地址计算整个数组的大小整个数组的地址
条件除了后面两种情况arr单独在sizeof内部任何时候

 再对比一下二维数组的数组名,以arr[10][10]为例:

arr第一行数组的地址
arr[0]

第一行数组名,是数组名就等于第一行第一个元素的地址

&arr整个数组的地址
&arr[0]第一行数组的地址
sizeof(arr)整个数组的大小
sizeof(arr[0])第一行数组的大小

总结:

  1. 只要arr不单独存在sizeof内部或者被取地址,那么都是首元素的地址。
  2. 二维数组的数组名是第一行数组的地址,二维数组使用下标访问符一次是某一行数组的名字,同时这种情况也要除去单独在sizeof内部和取地址。

(1)一维整形数组和sizeof

题目以及分析:
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));//数组总大小,4*4=16字节
printf("%zd\n", sizeof(a + 0));//数组首元素的地址,首地址+0=首地址,地址的大小是的4/8字节
printf("%zd\n", sizeof(*a));//a是数组首元素的地址,*a就是首元素,计算的就是首元素的大小,整形4字节
printf("%zd\n", sizeof(a + 1));//a是数组首元素的地址,地址+1跳过一个元素,那就是第二个元素的地址,4/8
printf("%zd\n", sizeof(a[1]));//第二个元素,整形int,4字节
printf("%zd\n", sizeof(&a));//&a取出的是数组整个元素的地址,还是地址,4/8

/*****************************重点******************************/
printf("%zd\n", sizeof(*&a));//不是单独的&a,a表示首元素的地址,&a是取出首元素的地址的地址,再解引用就是首元素的地址,4/8
printf("%zd\n", sizeof(&a + 1));//取地址a是整个数组的地址,+1跳过整个数组,地址是数组末尾元素后面的地址的,
							  //实际还是地址,sizeof只关注类型,不关注指针是否越界,
							  // 换句话说这个指针并没有被使用只是计算大小,所以是可以计算的
/****************************************************************/

printf("%zd\n", sizeof(&a[0]));//取出首元素的地址,是地址,4/8
printf("%zd\n", sizeof(&a[0] + 1));//取出首元素的地址,地址+1,跳过一个元素,第二个元素的地址,是地址,4/8
//正确率:错1,printf("%d\n", sizeof(*&a));
//正确理解1:&a是整个数组的地址,与&a单独作用无关,&a取出的就是整个数组的地址,解引用就是拿出整个数组,整个数组的大小就是16
//理解2:解引用*和取地址&相互抵消,剩下a,就是数组名,sizeof(a)==16
答案: 

(2).使用大括号存储的字符数组 

A.sizeof

题目以及分析:
	//字符数组,字符单个存储,只有abcdef这六个元素,没有'\0'
	printf("%zd\n", sizeof(arr));//sizeof操作时,单独只有个数组名时,整个数组的大小,1*6=6字节
	printf("%zd\n", sizeof(arr + 0));//arr表示数组首元素的地址,首元素的地址+0,就是首元素的地址,是地址,大小就是4/8
	printf("%zd\n", sizeof(*arr));//arr是数组首元素的地址,解引用首元素的地址就是首元素,字符char,1字节
	printf("%zd\n", sizeof(arr[1]));//第二元素,字符char,1字节
	printf("%zd\n", sizeof(&arr));//&arr是整个元素的地址,是地址,大小就是4/8
	printf("%zd\n", sizeof(&arr + 1));//整个数组的地址,地址是数组指针类型,+1跳过1个数组的大小,就是末元素后元素的地址,是地址,4/8
	printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]是取出首元素的地址,地址是字符指针,+1跳过一个元素,指向第二个元素,是地址,大小4/8
	//正确率:全对
答案: 

B.strlen

题目以及分析:
char arr[] = { 'a','b','c','d','e','f' };
//字符数组,字符单个存储,只有abcdef这六个元素,没有'\0'
printf("%zd\n", strlen(arr));//strlen函数计算字符个数,给的数组首元素的地址,strlen从这后向找,无\0,随机值
printf("%zd\n", strlen(arr + 0));//首元素地址+1还是首元素的地址,从首元素开始向后找,无\0,随机值
/*重点*/
//printf("%zd\n", strlen(*arr));//arr表示首元素的地址,首元素的地址解引用,得到第一个元素,就是a,
//因为,strlen函数的参数是地址,那么字符a就被转为它的ASCII码值,97,那么地址就是97,
//但是因为这个地址是个特殊地址,无法被访问,所以报错
//printf("%zd\n", strlen(arr[1]));//arr[1]表示第二个元素,那就是字符b,
//同样也被转为ASCII码值对应的数字98,地址98也是特殊地址无法访问
printf("%zd\n", strlen(&arr));//&arr是整个数组的地址,是数组指针,那就被转为字符指针,指针是首元素的地址,无\0,随机值
printf("%zd\n", strlen(&arr + 1));//&arr是整个数组的地址,+1跳过整个数组,
//地址就到末元素后面一个元素的地址,从这开始向后找,后面找不到'\0',就一直找下去,生成的随机值,随机值比第一个开始找的多6个
printf("%zd\n", strlen(&arr[0] + 1));//首元素的地址+1,到第二个元素的地址,从第二个元素向后找,没有斜杠0,随机值,
//比从第一个开始找的多一个数
//正确率:全对
//注意:1.特殊地址无法访问,会报错;2.大括号存字符无\0随机值
答案: 

(3).使用字符串存储的字符数组

A.sizeof

题目以及分析:
char arr[] = "abcdef";
//字符串存储,数组大小也没有限定,存完字符后后再存了一个'\0'
printf("%zd\n", sizeof(arr));//计算的是整个数组的内存大小,7*1=7个字节
printf("%zd\n", sizeof(arr + 0));//arr是数组首元素的地址,首元素的地址+0=首元素的地址,地址的大小,4/8
printf("%zd\n", sizeof(*arr));//arr是数组首元素的地址,首元素的地址解引用得到的是首元素,首元素的大小char,1个字节
printf("%zd\n", sizeof(arr[1]));//arr[1]是首元素,char,1个字节
printf("%zd\n", sizeof(&arr));//&arr是取出整个数组的地址,是地址,4/8
printf("%zd\n", sizeof(&arr + 1));//&arr是取出的整个数组的地址,数组指针类型,地址+1跳过整个数组,
//那就是末元素的下一个元素地址,是地址,4/8
printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]取出的是首元素的地址,首元素的地址+1跳过1个元素,那就是第二个元素的地址,是地址,4/8
//正确率:全对
答案: 

B.strlen

题目以及分析:
char arr[] = "abcdef";
//字符串存储,数组大小也没有限定,存完字符后后再存了一个'\0'
printf("%d\n", strlen(arr));//arr是首元素的地址,计算'\0'前的元素个数,6个
printf("%d\n", strlen(arr + 0));//arr是首元素的地址,+0还是首元素的地址,计算出6个元素
//printf("%d\n", strlen(*arr));//arr是首元素的地址,解引用得到首元素,字符a转换为ASCII码值97,97是个特殊地址无法访问,报错。
//printf("%d\n", strlen(arr[1]));//同上,arr[1]='b',转为ASCll码值98,特殊地址无法访问
printf("%d\n", strlen(&arr));//&arr取出的是整个数组的地址,而strlen的参数接收的是char*类型,就会进行强制类型转换,
//而整个数组的地址就是首元素的地址,那就是首元素的地址,从后计算得到6个元素
printf("%d\n", strlen(&arr + 1));//&arr取出的是整个数组的地址,+1就会跳过整个数组,到达\0后面
//拿到后面这个元素地址,注意这里操作的任然是地址,从这向后找,找不到'\0',随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0],第一个元素的地址,+1第二个元素的地址,从第二个元素开始计算,5个
//正确率:全对
答案: 

(4).使用指针存储常量字符串

A.sizeof

题目以及分析:
char* p = "abcdef";//首元素的地址
printf("%zd\n", sizeof(p));//p是一个指针,大小4/8
printf("%zd\n", sizeof(p + 1));//p+1跳过一个元素,b的地址,是地址,4/8
printf("%zd\n", sizeof(*p));//*p得到'a',char类型数据,1个字节
printf("%zd\n", sizeof(p[0]));//p[0]==*(p+0)==数组名[0]==第一个元素,char类型,1个字节
printf("%zd\n", sizeof(&p));//&p,取出第一个元素的地址的地址,是地址,4/8
printf("%zd\n", sizeof(&p + 1));//&p,取出第一个元素的地址的地址,+1跳过一个地址,还是地址,4/8
printf("%zd\n", sizeof(&p[0] + 1));//&p[0]==&p[0]==&*(p+0)=p,是地址,4/8
//正确率:全对
答案: 

B.strlen

题目以及分析:
char* p = "abcdef";//首元素的地址,常量字符串后面也有\0
printf("%zd\n", strlen(p));//从首元素开始计算,6个元素
printf("%zd\n", strlen(p + 1));//首元素地址+1,从第二个元素开始计算,5个元素
//printf("%d\n", strlen(*p));//*p是'a',转为ACSII码值97,特殊地址,无法访问,报错
//printf("%d\n", strlen(p[0]));//p[0]==数组名[0]==*(p+0)==*p=='a',同上,报错
printf("%zd\n", strlen(&p));//&p,取出地址的地址,从后计算,找不到'\0',随机值
printf("%zd\n", strlen(&p + 1));//&p,取出地址的地址,+1跳过一个地址,从后计算,找不到'\0',随机值
printf("%zd\n", strlen(&p[0] + 1));//&p[0]+1==&*(p+0+1==p+1,从第二个元素向后计算,5
//正确率:全对
答案: 

(5).二维数组和sizeof

B.strlen

题目以及分析:
//二维数组数组名是第一行数组的地址,&数组名是取出整个数组的地址
int a[3][4] = { 0 };
printf("%zd\n", sizeof(a));//数组单独存在sizeof的内部,计算的是整个数组的大小,3*4*4=48
printf("%zd\n", sizeof(a[0][0]));//第一行第一列元素啊,int类型,4个字节
//重点//
printf("%zd\n", sizeof(a[0]));//第一行数组名字,单独放在sizeof的内部,计算第一列数组的大小,4*4=16
printf("%zd\n", sizeof(a[0] + 1));//第一行第一个元素地址+1==第一行第二列元素地址,4/8
printf("%zd\n", sizeof(*(a[0] + 1)));//解引用第二列数组,计算数组大小,4*4=16
//
printf("%zd\n", sizeof(a + 1));//a是第一行的地址,+1第二行,还是地址,4/8
printf("%zd\n", sizeof(*(a + 1)));//a是第一行数组的地址,+1第二行,解引用是数组,4*4=16
printf("%zd\n", sizeof(&a[0] + 1));//取出第一行的地址,+1第二行的地址,是地址,4/8
printf("%zd\n", sizeof(*(&a[0] + 1)));//第二行的地址解引用,第二行数组大小,4*4=16
printf("%zd\n", sizeof(*a));//a是第一行的地址,解引用是第一行的数组大小,4*4=16
printf("%zd\n", sizeof(a[3]));//第四行数组名单独在sizeof内部,计算的是数组大小,虽然越界,但没使用,底层是类型,4*4=16
//正确率:错一个,printf("%d\n", sizeof(*(a[0] + 1));
错误分析:解引用第二列数组,计算数组大小,4*4=16
正确分析:第一行数组名表示第一行数组第一个元素的地址,得到元素,int,4个字节
答案: 

总的来说只要理解了sizeof和strlen的作用,知道数组名不同场景下所表示的含义这种题目就很简单啦!!!


本章内容结束,我们下章见,拜拜!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值