一、数组名的问题
从网络上看到这样一道有意思的题目,是关于数组与指针的问题,描述如下:
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1); //a类型是指向一个元素,而&a类型是指向一行
printf("%d,%d",*(a+1),*(ptr-1));
}
输出为:2,5
请解释以上代码的输出结果。
答案如下:
*(a+1)其实很简单就是指a[1],输出为2.
问题关键就在于第二个点,*(ptr-1)输出为多少?
解释如下,&a+1不是首地址+1,系统会认为加了一个整个a数组,偏移了整个数组a的大小(也就是5个int的大小)。所以int *ptr=(int *)(&a+1);其实ptr实际是&(a[5]),也就是a+5.
原因为何呢?
&a是数组指针,其类型为int(*)[5];
【注意,经过测试&a不是个左值了,是个右值了,也就是个常量了,所以上面说法不完全对,&a不是指针,只是个地址值,但任何数值也都是有类型的,比如5.0或1.234都是double型的。既然&a是个数组这种数据结构类型的一个值,那么它的算术运算也就按这种类型的要求计算了,所以+1就是加了整个数组的长度。】
【虽然a和&a这两个东西的值都是一样的,都等于数组第一个元素的首地址值,但这两个东西的类型不一样,甚至这两个东西一个是左值即变量,一个是右值是常量。其实,不仅是数组名,函数名也和这个类似。】
而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同,a是长度为5的int数组指针,所以要加5*sizeof(int),所以ptr实际是a[5],但是ptr与(&a+1)类型是不一样的,这点非常重要,所以ptr-1只会减去sizeof(int*),a,&a的地址是一样的,但意思就不一样了,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]。
【总结:以后不管那么多,只需记住:对于a,前面加个&符号也就是&a,则&a的类型比a的类型扩大(比如a指向一个元素,则&a则指向一行元素,对于二维数组若b指向一行元素,则&b指向多行元素);对于a,前面加个*符号也就是*a,则*a的类型比a的类型缩小。】