1.sizeof与strlen的介绍
(1).sizeof
- 计算变量的内存空间大小。
- 底层实际上是对变量类型的计算。
- 是一个单目操作符,不是函数,后面的括号可以省略
(2).strlen
- strlen是一个函数,返回的size_t类型的数据,头文件为string.h
- 计算字符串'\0'前的字符个数,计算字符长度
- 如果没有找到'\0'就继续往下找,通常对于没有'\0'的字符生成的是一个随机值
- 函数通过首元素的地址往下找。
(3)sizeof与strlen对比
对比 | sizeof | strlen |
所属类型 | 单目操作符 | 库函数 |
计算内容 | 元素的内存空间大小 (单位:字节) | 元素的个数 |
特性 | 1.括号可有可无 2.只关注变量的类型 3.不关注变量中的数据是啥 | 1.通过地址往后找 2.找到' \0 '后结束 3.找不到' \0 '一直向后找 |
2.sizeof和strlen的使用
下面通过使用sizeof和strlen对数组进行操作的例子来加深我们的理解吧
在举例前我们先要知道数组和sizeof(数组名),以及取地址数组名的区别:
对比一维数组的数组名,以arr[10]为例:
对比 | arr | sizeof(arr) | &arr |
含义 | 数组首元素地址 | 计算整个数组的大小 | 整个数组的地址 |
条件 | 除了后面两种情况 | arr单独在sizeof内部 | 任何时候 |
再对比一下二维数组的数组名,以arr[10][10]为例:
arr | 第一行数组的地址 |
arr[0] | 第一行数组名,是数组名就等于第一行第一个元素的地址 |
&arr | 整个数组的地址 |
&arr[0] | 第一行数组的地址 |
sizeof(arr) | 整个数组的大小 |
sizeof(arr[0]) | 第一行数组的大小 |
总结:
- 只要arr不单独存在sizeof内部或者被取地址,那么都是首元素的地址。
- 二维数组的数组名是第一行数组的地址,二维数组使用下标访问符一次是某一行数组的名字,同时这种情况也要除去单独在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的作用,知道数组名不同场景下所表示的含义这种题目就很简单啦!!!
本章内容结束,我们下章见,拜拜!!!