甲:“这个问题深啊!”
我:“深?!我这深的多着那!”
且听我细细道来!
首先,得给大家讲一个目前国内(含国外,赫赫)所讲到的指针概念中都涉及,但都没有足够清晰解释的一个关于指针的概念:
指针有两个要素:
1、首地址(学过C的都知道)
2、指类(朱某人的专用术语):指针所指向的空间的类型。
指类的概念非常重要,是比首地址概念更重要、更要命的概念,原因如下:
指针之间的操作必须保证指针指类的一致性,如果参加运算的两个指针的指类不同,则至少会有编译的警告,多数是错误报告;
指针+(-)整型量,能使指针的指向发生更改,而更改量取决于指类长度!即,指针+1将得到
指针值+sizeof(指针指类)的效果。
指针指类的判别方法是:在定义指针、数组的语句中,去掉一个*,剩余的内容与基本类型结合,就成为指类。例如:
char *cp;//去掉一个*,类型部分只剩char,那么char就是cp的指类;或者说,C语言对于cp所指向的空间仅按char解释。
float **pfp;//去掉一个*,类型部分是float *,那么float *就是fpf的指类;或者说,fpf指向类型为(float *)的指针空间(变量)(这里我用空间而不用变量,因为变量这个名词太混乱,简直就是一本混账);
int *ar[10];//这里要复杂些。首先在定义数组ar的语句中,有两个符号:*和[],按优先级,[]优先于*,因此[]优先与ar结合;此时将结合不是很紧密的部分与ar[10]分开,将得到:
int*
ar[10];从这里可以很清楚的知道,int*是数组ar的每个元素的类型,而ar是数组;
int (*ar)[10];//这个更复杂。由于()的存在,*与ar优先结合,此时可以将[10]前置,与int组合成:
int[10]
*ar;从这里可以很清楚地知道,int[10]是指针变量ar的指类,ar是指针变量!
接着,由于ar的指类是int[10](由10个int元素组成的一段连续存储空间,为40B),长度为40B,所以ar+1将移动40B!
有了这些知识了,我们可以看楼主提出的问题了:
int main()
{
int a[4]={1,2,3,4};
int *ptr1=(int*)(&a+1);
//这里&a是表达式,而且是指针表达式,且这个指针的指类是a的类型,是int[4];这是最关键的地方!
//&a+1,是典型的指针+1运算,按照我的理论,将使指向向后移动16B,指向数组a所申请的空间的下一个字节!
//也就是说,ptr1现在实质上指向了&a[4](这个地址所表示的字节是不以人的意志为转移而存在的!)
//那么,后面的ptr1[-1]很明显就是a[3]了!
int *ptr2=(int*)((int)a+1);
//这里更微妙:
//首先看数组的数据在内存中的映像:
01(每行是一个字节,这里我用的是高高低低原则:高位数存放在高端字节(地址编号较大的字节))
00 //下面的操作,使ptr2指向这里 (
新开始)
00
00(上面4个B组成第一个元素)
02 //从新开始到这里,形成由ptr2所指向的int类型的“变量”(此时如果换成“空间”,那么就不存在感情上的问题了)
00
00
后面省略
int *ptr2=(int*)((int)a+1);
//首先将a强制转换成int类型,那么它+1就是实实在在的+1,那么ptr2将指向上面所述的位置。此时再输出*ptr2,自然就会得到:02 00 00 00(对应十进制数:33554432)
printf(" %x\n %x\n",ptr1[-1], *ptr2);
return 0;
}
请大家验证!
建议将输入改为:
printf(" %p %p %p %d %d\n", a, ptr1, ptr1, ptr1[-1], ptr2[0]);
那就能清晰了。