我正在寻求有关地址递增如何影响指针的解释。
我通过考虑指针类型了解了C指针如何工作以及如何增加指针。我还是不明白以下情况
int main()
{
int a[] = {1,2,3,4,5};
int *p = (int*)(&a+1);
printf("%d\n%d\n", *(a+1), *(p-1));
return 0;
}
我希望这条线
int *p = (int*)(&a+1);
使p
指向数组a
之后的地址,因此我期望输出:
2
原为a[1]
但是输出是unknown_number-因为我不知道哪个int在(&a+1)
之后4个字节
实际结果是:
2
5
为什么p
似乎直接指向a
之后的内存?
我困惑的根源是什么?
两个基本概念:
除了是sizeof
或一元&
运算符的操作数,还是用于初始化声明中的字符数组的字符串文字,expression类型为“ N元素数组” T
“的值将被转换(“衰变”)为类型为“ T
的指针”的表达式,该表达式的值将为数组第一个元素的地址。
向“指向T
的指针”类型的表达式中加1会产生紧随当前对象之后的T
类型的对象的地址。 IOW,如果p
指向4字节int
,则p+1
指向紧随其后的int
。如果p
指向int
的5元素数组,则p+1
指向紧随其后的int
的下一个5元素数组。这就是数组索引的工作方式-下标操作a[i]
定义为*(a + i)
。给定起始地址a
(指针表达式或衰减到指针的数组表达式),请在该地址后找到第i
个object的地址,然后取消对结果的引用。
因此,如果您有声明
int a[] = {1, 2, 3, 4, 5};
那么,以下为真:
expression a
的类型为“ int
的5元素数组”(int [5]
)-如果表达式不是sizeof
的操作数或一元&
运算符,它“衰减”以键入“指向int
的指针”(int *
),其值是数组第一个元素的地址(&a[0]
)。
表达式*(a + 1)
与a[1]
相同,并且求值为数组(2
)中的第二个对象。
表达式&a + 1
具有类型int (*)[5]
,并在int
之后产生a
的5元素数组的起始地址。该表达式的类型转换为int *
并分配给p
。
表达式p
的类型为int *
-从中减去1会得出int
紧接在前的p
对象的地址,该地址恰好是a
的最后一个元素。
图解:
+–––+
a: | 1 |
+–––+
| 2 | <–– a + 1
+–––+
| 3 |
+–––+
| 4 |
+–––+
| 5 | <–– p - 1
+–––+
| ? | <–– p (&a + 1)
+–––+
因此,在此示例中,&a
的类型为int(*)[5]
。当您向其添加1时,它实际上会添加sizeof(int[5])
-因为这是指针算术的工作方式,因此添加偏移量将指向的类型的大小乘以偏移量。这就是使p
成为a
的最后一个元素之后的方式,然后将其强制转换为int*
,因此现在您有了一个指针,该指针指向a
的最后一个元素之后的地址处的整数。 。因此,从中减去1可以得到a
的最后一个元素。
您可以将数组a
用作指向int int *
的指针。但是对于&a
来说,这是不一样的,它是一个指向5个整数的数组的指针:&a + 1
会将5个整数的大小添加到该指针。