叠甲:纯新人学习,讲的都是很简单的内容,就是想让我这种傻瓜也看得懂的,不喜勿喷。有错误或者不好的地方可以帮忙指出,非常感谢!
接着上面的故事
第三板块
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
第三板块 printf打印的结果是什么?整体的答案在这道题结束时公布。现在我们来一条一条看(先代码后解释,别看错位置了)
看之前做个小区分,第二板块的=号后面是{}的,而这里是"",两种是有区别的(看图)
sizeof部分
printf("%d\n", sizeof(arr));//7
这里的arr代表整个数组,该数组有6个元素且是char类型,输出6。对吗?错误!别忘了字符串还有结束标准符,占一个字节哦,输出7
printf("%d\n", sizeof(arr + 0));//32-4 64-8
这里的arr+0的arr代表首元素地址,首元素+0,还是首元素地址,是地址就32-4 64-8
printf("%d\n", sizeof(*arr));//1
*arr就是解引用首元素地址,解出来是首元素,首元素是‘a' 这里是char类型,输出1
printf("%d\n", sizeof(arr[1]));//1
第二个元素‘b',且是char类型,输出1
printf("%d\n", sizeof(&arr));//32-4 64-8
取整个数组的地址,是地址就 32-4 64-8
printf("%d\n", sizeof(&arr + 1));//32-4 64-8
这里arr代表整个数组,取整个数组的地址+1,还是个地址,是地址就32-4 64-8
printf("%d\n", sizeof(&arr[0] + 1));//32-4 64-8
取arr[0]的地址+1,还是个地址,是地址就32-4 64-8
strlen部分
printf("%d\n", strlen(arr));//6
arr单独使用代表整个数组,这里传进去整个数组的地址,而数组的地址是首元素的地址,于是strlen就从首元素地址开始算,到\0停止,输出6
printf("%d\n", strlen(arr + 0));//6
arr+0代表首元素地址+0,还是首元素地址,从首元素开始算,\0结束,输出6
printf("%d\n", strlen(*arr));//error
printf("%d\n", strlen(arr[1]));//error
解引用arr,解出来就是arr首元素‘a’,这不是一个合法的传址,编译器会报错
同理 arr[1]就是arr第二位元素‘b’,这不是一个合法的传址,编译器会报错
printf("%d\n", strlen(&arr));//6
这里的arr代表整个数组,&arr的就是取整个arr的地址,而arr的地址就是首元素地址,从首元素开始,到\0结束,输出6
printf("%d\n", strlen(&arr + 1));//随机值
这里的arr代表整个数组,&arr就是取整个arr的地址,&arr+1就是跳到下一个数组去了。那么下一个数组的\0在哪呢?我们不知道,所以是随机值
printf("%d\n", strlen(&arr[0] + 1));//5
&arr[0]就是取了arr数组0位的地址,就是arr数组首元素的地址。&arr[0]+1就是第一位的地址+1,这就跳到第二位去了,所以strlen从第二位开始算,到\0结束 输出5
答案(64位平台 就是地址是 8的)
-------------------------------------------------------------------
第四板块
char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));
第四板块 printf打印的结果是什么?整体的答案在这道题结束时公布。现在我们来一条一条看(先代码后解释,别看错位置了)
sizeof部分
printf("%d\n", sizeof(p));//32-4 64-8
p指针是个地址,所以 32-4 64-8
printf("%d\n", sizeof(p + 1));//32-4 64-8
p指针是个地址+1还是个地址,还是32-4 64-8 你懂的
printf("%d\n", sizeof(*p));//1
p指向的是首元素地址,解引用p,就是解引用首元素地址,得出a,char类型的,在内存占1个字节空间,所以输出1
printf("%d\n", sizeof(p[0]));//1
等价*(p+0) 解引用p+0,还是解引用首元素地址,得出a,char类型的,在内存占1个字节空间,所以输出1
printf("%d\n", sizeof(&p));//32-4 64-8
取指针p自身地址然后放进sizeof,sizeof就是算操作数在内存上所占空间大小的,地址所占空间大小就 32-4 64-8
printf("%d\n", sizeof(&p + 1));//32-4 64-8
取指针自身地址+1,不还是地址,是地址就是32-4 64-8
printf("%d\n", sizeof(&p[0] + 1));//32-4 64-8
依然是取地址+1,还是地址。32-4 64-8
"这是什么情况,怎么和想象的不一样,怎么错那么多"---这是我做完时的心里话,这个确实有点难懂的感觉,当然只是感觉。我画了个图,我敢保证这个图看懂了,你就懂了
有了这个图,我们下面的strlen部分就简单了
strlen部分
printf("%d\n", strlen(p));//6
由上图所示,p指向字符串首元素的地址,这里的strlen也就从首元素开始算,遇到\0停止,输出6
printf("%d\n", strlen(p + 1));//5
由上图所示,p指向字符串首元素地址,+1就是字符串首元素地址+1,指向了第二位元素地址,这里strlen就从第二位开始算,遇到\0停止,输出5
printf("%d\n", strlen(*p));//error
由上图所示,解引用p,得到的是首元素a,给strlen传这种地址是非法的,编译器报错
printf("%d\n", strlen(p[0]));//error
p[0]就是*(p+0),解出来就是首元素a,这种传址方式是非法的,编译器报错
printf("%d\n", strlen(&p));//随机值
取地址指针p,注意是取到了指针自身的地址,这边strlen要遇到\0才会停,我们不知道\0在哪,输出随机值。
printf("%d\n", strlen(&p + 1));//随机值
取地址指针p再+1,就是取指针自身地址+1,还是和上条一样,我们不知道\0在哪,输出随机值
printf("%d\n", strlen(&p[0] + 1));//5
可以理解为&(*(p+0))+1, *(p+0)得到首元素,这里取首元素地址再+1,得到第二个元素地址。strlen从第二个元素开始算,遇到\0停止。输出5
答案(64位平台 就是地址是 8的)
-------------------------------------------------------------------
第五部分 最难的来了
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
第五板块 printf打印的结果是什么?整体的答案在这道题结束时公布。现在我们来一条一条看(先代码后解释,别看错位置了)
开始前请仔细看下面两图,分清楚一二维数组各自的区别和相同点
开始
printf("%d\n", sizeof(a));48
a表示整个二维数组 3*4*sizeof(int)=48
printf("%d\n", sizeof(a[0][0]));//4
表示二维数组的第一行第一列元素,int类型,输出4
printf("%d\n", sizeof(a[0]));//16
表示二维数组的首元素,也可以表示二维数组的第一行。有四个元素,都是int类型,输出16
printf("%d\n", sizeof(a[0] + 1));//32-4 64-8
printf("%d\n", sizeof(*(a[0] + 1)));//4
a[0]也是二维数组的中第一行一维数组的数组名,这里没有单独使用,也没有取地址。代表第一行第一列地址,+1,就是第一行第二列地址了,是地址就32-4 64-8
同理,解引用第一行第二列地址就得出第一行第二列的元素,int类型,输出4
printf("%d\n", sizeof(a + 1));//32-4 64-8
printf("%d\n", sizeof(*(a + 1)));//16
a是二维数组的数组名,这里没有单独使用,代表首元素地址,+1,就是第二行(能懂吧?)地址
地址就32-4 64-8
a是二维数组名,没有单独使用,代表首元素地址,二维数组首元素是a[0],+1就是a[1]的地址,解引用,4个int得出16
printf("%d\n", sizeof(&a[0] + 1));//32-4 64-8
printf("%d\n", sizeof(*(&a[0] + 1)));//16
a[0]也是二维数组的中第一行一维数组的数组名,这里被取地址,那就代表二维数组中第一行一维数组的整个数组,+1就跳到第二行一维数组去了。由于是取地址,所以输出4
同理,解引用第二行地址得出整个第二行(一维数组),4个int,输出16
printf("%d\n", sizeof(*a));//16
a是二维数组的数组名,这里没有单独使用也没有取地址,所以代表二维数组首元素,二维数组首元素是a[0],解引用地址得到第一行,4个int类型,输出16
printf("%d\n", sizeof(a[3]));//16
这是什么东东?怎么有a[3],这不越界访问了吗?
nonono
在C语言中,一条表达式有两种属性。分别是值属性和类型属性
比如int a=1+2这条表达式里面,值属性是3,类型属性是int
越界访问那是要算(被用到)时才会发生的
比如sizeo(1+2),它内部表达式是不计算的,也就是说是不会去算这个1+2等于什么的,而且直接推测他的类型
上面也是,直接根据int和[3][3]推测a[3]是什么类型的空间大小多少,不会真的去访问那块区域
答案(64位平台 就是地址是 8的)
part2结束
以上!