引言:上篇博文,我们针对C语言的灵魂-指针进行了深度探究,为了巩固所学,推出这篇博文,目的在于加深理解和应用所学。
作者:小 琛
欢迎转载,请标明出处
数组和sizeof()
前面我们谈到过,sizeof()是一个可以用来计算数组长度的运算符,而数组是一个和指针密切练习的东西,接下来我们看关于它的题目
#include <stdio.h>
int main()
{
int a[] = { 1, 2, 3, 4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
结果如下:
我们先仅仅看一道这类题目,进行分析讲述。
1、sizeof() 的结果等于对象或者类型所占的内存字节数,例如sizeof(int)就等于4
2、sizeof()仅仅确定一下答案,并不改变其值,它是一个优秀的员工,完成自己的工作同时并不会影响他人。
例如:
int a=10;
printf("%d,%d",sizeof(++a),a)
结果等于:4,10
由此就可以证明,在sizeof()内进行运算例如自加,不会影响这个变量本身的数值。
3、sizeof在进行数组运算的时候,若括号内为首元素地址,则计算整个数组大小,该定则要保证该首元素的地址没有进行任何运算,若给予括号内其它数组元素元素地址,将会被当作一个普通指针运算,而我们知道指针的大小恒为4,也就能解释上面的倒数第三题
有了上述知识,我们再做些练习
#include <stdio.h>
int main()
{
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", sizeof(arr));//数组名代表首元素地址,结合第三条,计算整个数组大小
printf("%d\n", sizeof(arr + 0));//这个不好理解,首元素地址一旦进行运算,将不再代表数组即使是加了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));
return 0;
}
结果如下:
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%c\n", arr[0]);//arr数组仍是给了该字符串的每个字符一个单元,结果为a
printf("%d\n", sizeof(arr));//这里注意每个字符串的结尾都有一个\0,因此有7个成员
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));
return 0;
}
结果:
学到这里,会有一个非常容易搞混淆的题:
#include <stdio.h>
int main()
{
char *p = "abcdef";
printf("%d\n", sizeof(p));//这里的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));
return 0;
}
注意第一题,sizeof§,虽然p是首元素地址且没有进行运算,但它不能计算整个字符串的大小。大家千万别搞混淆,前面讲到的定则是数组专用的,其它无关人士并不具备!
接下来就是一个难点,二维数组,先看题目:
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]));
在做题前,我们先学习相关知识,否则会非常吃力。
1、对于二维数组,它在储存上其实可以看作是一个特殊的一维数组,其图形可以这样画:
也就是说,二维数组仅仅是在逻辑上二维,而物理上也是连续存储的。因此我们可以把二维数组看作n个一维数组,如上图,每个颜色代表一个一维数组,而组合起来就是这个二维数组
2、sizeof()对于一维数组的定则同样适用于二维数组,即:sizeof在进行数组运算的时候,若括号内为首元素地址,则计算整个数组大小,该定则要保证该首元素的地址没有进行任何运算
3、若一个二维数组,仅仅给了一个中括号,例如a[2]则可视为 第2行这个一维数组,即上图中绿色部分
4、二维数组名可以看成一个二级指针,若计算sizeof(a+1),则要注意,a是二维数组的首元素地址,它进行了加1运算,首先必然不能代表这个二维数组,但它同样不能代表第二行的那个一维数组,因为该变量仍然是一个二级指针,也就是它的本质仍然是针对二维数组的,因此仅仅是一个指针。但假如对它进行解引用*(a+1),这是从二级指针变为一级指针,则可以代表第二行的那个一维数组的首元素地址,运算答案将是 16
整道题答案如下:
总结:
类似的题目,其实都有本质规律,只要按照笔者给出的办法,一步步判断它是什么,就可以解答。切记:先看数组是几维,再看该地址是否为首元素地址且没有进行运算,若不是则是一个普通指针,否则代表整个数组
指针类的题目
1、
#include <stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
答案:2,5
注意区分&a与a,这里的ptr指针是一个二级指针,a本身是首元素地址,又取地址符,那就是二级指针,它加1,相当于指向了该数组后面的存储单元,再减一解引用到5
2、
#include <stdio.h>
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int*)(&a + 1);
int *ptr2 = (int*)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
细看上面的分析,结果则就是:4,20000000
3、
#include<stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式,总是取后一个的值
int *p;
p = a[0];
printf("%d", p[0]); //p[0]相当于*(p+0)
return 0;
}
分析:
这道题的考点很隐蔽,也很容易出错。首先,在数组的定义时,使用了逗号表达式,很多人都会误以为时一个全部赋值的二维数组,即应当如下图:
逗号表达式:取括号内的后值
结合图,定义的p指针应当指向1处,而再对p进行运算p[0],可以换算为:
*(p+0)
综上,输出结果:1
4、
#include<stdio.h>
int main()
{
int a[5][5];
int (*p)[4]=(int(*)[4])a;
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
}
5、
#include<stdio.h>
int main()
{
char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
char **cp[] = { c + 3, c + 2, c + 1, c };
char ***cpp = cp;
printf("%s\n",**++cpp);
printf("%s\n",*--*++cpp+3);
printf("%s\n",*cpp[-2]+3);
printf("%s\n",cpp[-1][-1]+1);
return 0;
}
笔者这里就不分析了,给一张图,读者可自行结合规则分析
结果如下:
本文到此结束,谢谢浏览
转载:https://blog.csdn.net/qq_44745063/article/details/102559974