目录
本章将通过列题进一步了解sizeof 与strlen的区别,加强对数组的理解。
1:一维数组列题
2:字符数组列题
3:二维数组列题
首先在进行这些习题讲解之前我们需要知道的知识点
sizeof:是一个关键字,可以计算变量,数据类型,函数所占空间的大小,单位是字节,计算的时候只关心数据类型。
strlen:是一个标准库函数,头文件是 <striing.h>,是用来计算字符串\0前面的字符的个数,strlen(数组名)。
还有对于数组名的理解:除了2种情况下数组名就是首元素的地址,1:单独使用sizeof(数组名),这里的数组名指的是整个数组。2:&数组名,这里的数组名代表的是整个数组,所以&数组名代表的是整个数组的地址,它的指向也是数组的首元素的地址,但是在进行指针加减整数的时候跳过的是整个数组。
1:一维数组列题
#include<stdio.h>
int main()
{
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//这里是特殊的情况,所以计算的是整个数组的大小 16
printf("%d\n",sizeof(a+0));
//这里的a是首元素的地址,+0后还是首元素地址,而地址(指针)的大小为4/8
printf("%d\n",sizeof(*a));
//a是首元素的地址,所以*a则代表数组中的第一个元素,所以大小为一个int的大小 4
printf("%d\n",sizeof(a+1));
//a代表数组首元素的地址,+1则代表指针指向2的地址,还是个地址所以大小为 4/8
printf("%d\n",sizeof(a[1]));
//a[1],代表数组中第二个元素即2,所以大小为int的大小 4
printf("%d\n",sizeof(&a));
//这里的a是特殊情况,所以a代表整个数组,但是&a还是一个地址 所以大小为 4/8
printf("%d\n",sizeof(*&a));
//这里有两种理解方式
1:&a是代表数组的地址,* &a则代表数组 所以大小为数组的大小 16 *& 相当于没有
2:&a本质上是数组指针,类型为int (*)[4],解引用后为类型int [4] 还是整个数组 16
printf("%d\n",sizeof(&a+1));
//&a+1代表的是地址,所以大小为4/8 但是在内存中表示为指针跳过整个数组,指向数组最后一个元素的后面
printf("%d\n",sizeof(&a[0]));
//这里就直接表示为取出第一个元素的地址,大小为 4/8
printf("%d\n",sizeof(&a[0]+1));
//这里表示第2个元素的地址,也是4/8,指针加一跳过一个int
}
这是在32位平台下的结果
64位平台下的结果
图解:a,a+1,&a,&a+1,&a[0],&a[0]+1
2字符数组
形式1:
//关于sizeof
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
//这里代表整个数组的大小,为 6
printf("%d\n", sizeof(arr+0));
//这里的arr代表数组的首元素的地址,所以为 4/8
printf("%d\n", sizeof(*arr));
//这里的arr代表数组首元素的地址,所以*arr代表字符'a' 为1
printf("%d\n", sizeof(arr[1]));
//arr[1]代表,'b' 为1
printf("%d\n", sizeof(&arr));
//&arr代表整个数组的地址,所以为 4/8
printf("%d\n", sizeof(&arr+1));
//&arr+1表示跳过数组arr,指向下一个数组 4/8
printf("%d\n", sizeof(&arr[0]+1)); //也等于&arr[1]
//这里代表取出 字符'b'的地址,也是 4/8
// 关于strlen
printf("%d\n", strlen(arr));
//这里的值为随机值,因为不知道内存中/0在哪
printf("%d\n", strlen(arr+0));
//这里的arr还是指的是数组首元素的地址,而strlen需要一个字符串,所以代码是error的
printf("%d\n", strlen(*arr));
//这里的*arr代表的是'a',而我们strlen需要char* 的参数,而'a'的asc码值为97,则会将代码段区域的 //地址传给strlen,这段代码块不是我们的内存,所以会形成非法访问内存的情况,所以也是error的
printf("%d\n", strlen(arr[1]));
//这里arr[1],代表的是'b',同理也是错误的只是asc变成98了 error
printf("%d\n", strlen(&arr));
//&arr代表的是整个数组的地址,但是它的值还是第一个元素的地址,沿着第一个元素向后寻找,所以也为随机值
printf("%d\n", strlen(&arr+1));
//同理,这是代表跳过数组后的地址,也是随机值,与前面一个相差 6
printf("%d\n", strlen(&arr[0]+1));
//这里代表'b'的地址,与arr差值为1
32位平台下:
64位平台下:
形式2:
int main()
{
char arr[] = "abcdef";//字符串中多了一个 '\0'
printf("%d\n", sizeof(arr));
//这里的arr代表整个数组,所以 大小为 7
printf("%d\n", sizeof(arr + 0));
//arr代表数组首元素地址 所以为 4/8
printf("%d\n", sizeof(*arr));
//arr代表数组首元素,*arr则代表数组中的第一个元素 1
printf("%d\n", sizeof(arr[1]));
//arr[1]代表 'b',所以值为 1
printf("%d\n", sizeof(&arr));
//&arr代表整个数组的地址 大小 4/8
printf("%d\n", sizeof(&arr + 1));
//&arr+1代表跳过一个数组的地址, 4/8
printf("%d\n", sizeof(&arr[0] + 1));
//这里表示指向'b'的地址 4/8
printf("%d\n", strlen(arr));//strlen求得是字符串'/0'前面的元素个数
//arr,表示数组的首元素地址, 6
printf("%d\n", strlen(arr + 0));
//arr还是数组首元素的地址 6
printf("%d\n", strlen(*arr));
//*arr代表的是'a',asc为97,strlen需要char* 所以改语句是error的
printf("%d\n", strlen(arr[1]));
//这个arr[1]代表数组的第2个元素即'b'同理,也会error
printf("%d\n", strlen(&arr));
//表示数组的地址,但是值还是与&arr[0]相等 6
printf("%d\n", strlen(&arr + 1));
//这个为随机值,&arr+1代表跳过整个数组后的地址 随机值
printf("%d\n", strlen(&arr[0] + 1));
这个代表的是'b'的地址,所以值为 5
}
32位平台:
64位平台下:
为了理解上面的两个字符串的差异,我们可以通过画图来理解:
常量字符串:
char *p = "abcdef";//首先这个代码的理解是在代码段中存储着"abcdef"这个字符串,而p则是代表存储着这个字符串的地址
printf("%d\n", sizeof(p));
//这里的p是一个字符指针,所以大小为 4/8
printf("%d\n", sizeof(p+1));
//指针加1且为char*指针,p+1代表指向b的地址 4/8
printf("%d\n", sizeof(*p));
//char*指针解引用只访问1个字节内容,*p代表 'a' 1
printf("%d\n", sizeof(p[0]));
//p[0]表示*(p+0)-->*p 'a' 1
printf("%d\n", sizeof(&p));
//&p代表的是指向p地址的指针,是一个char**指针 4/8
printf("%d\n", sizeof(&p+1));
//&p+1是跳过1个字符指针的指针 4/8
printf("%d\n", sizeof(&p[0]+1));
//即&p[1]-->&(p+1),也就是b的地址 4/8
printf("%d\n", strlen(p));
//p的值为a的地址 6
printf("%d\n", strlen(p+1));
//p+1代表'b'的地址 5
printf("%d\n", strlen(*p));
//error的*p为 'a'
printf("%d\n", strlen(p[0]));
//error p[0],代表的是'a'
printf("%d\n", strlen(&p));
//随机值,这里的&p代表的是存储p的地址 随机值
printf("%d\n", strlen(&p+1));
//这里是跳过一个二级字符指针后面的地址 随机值
printf("%d\n", strlen(&p[0]+1));
//这里代表首元素地址+1,表示'b'的地址所以值为 5
3:二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
//这里的a代表的是整个数组,所以值为 48
printf("%d\n",sizeof(a[0][0]));
//a[0][0]代表第一个元素 4
printf("%d\n",sizeof(a[0]));
//a[0]可以看作二维数组的首元素为一个一维数组 16
printf("%d\n",sizeof(a[0]+1));
//a[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表示首元素的地址,即1维数组的地址 int(*)[4],+1则代表指向第二个一维数组的地址 4/8
printf("%d\n",sizeof(*(a+1)));
//表示第二个一维数组 大小为 16
printf("%d\n",sizeof(&a[0]+1));
//&a[0]表示一维数组的地址,类型为int(*)[4],+1则代表指向第二个二维数组的地址 4/8
printf("%d\n",sizeof(*(&a[0]+1)));
//第二个二维数组的大小 16
printf("%d\n",sizeof(*a));
//a代表首元素的地址,即一维数组的地址,*a则代表一位数组 16
printf("%d\n",sizeof(a[3]));
//a[3],虽然数组存在越界,但是sizeof只关注类型,所以a[3] 16
32位平台下:
64位平台下:
总而言之,我们需要知道核心的知识点才不会被题目带偏。
感谢观看!