为什么指针减法会产生与指向的值无关的数字?

问题描述 投票:0回答:3
#include <stdio.h>

void main() {

    int arr[] = {10,20,30,40};
    int *p1 = arr;
    int *p2 = &arr[2];

    printf("%d",p2-p1);
}

输出:2

我很惊讶地看到输出为 2。我不知道为什么输出是 2。

c pointers pointer-arithmetic
3个回答
1
投票
int arr[] = {10,20,30,40};


arr     | 10  | 20  | 30  | 40
index   |  0  |  1  |  2  |  3
pointer | @+0 | @+1 | @+2 | @+3

int *p1 = arr;
int *p2 = &arr[2];

这意味着,p1 指向 arr 的首地址,即 @,p2 指向 arr 的第三个元素,即 @+2

printf("%d",p2-p1);

p2-p1 => @+2 - @ = 2 所以输出是2


0
投票

当您从

p1
中减去
p2
时,即
(p2 - p1)
,您实质上是找到了它们内存地址之间的差异。由于两个指针都指向同一数组中的元素,因此它们的地址之间的差异表明它们在数组中相距多少个元素。所以,
p2 - p1
给你2,表示有2个整数(或元素,因为
int
,每个元素有4个字节)。

如果您想访问该值,可以通过

printf("%d",*p2-*p1);

来实现

0
投票

在此声明中

int *p1 = arr;

数组指示符隐式转换为指向其第一个元素的指针。它相当于下面的声明

int *p1 = &arr[0];

arr[i]
这样的表达式,其中
i
是某个整数,其计算方式类似于
*( arr + i )
。也就是说,表达式
a[0]
的计算结果与
*( a + 0 )
相同,与
*( a )
*a
相同。表达式
a[2]
的计算方式与
*( a + 2 )
类似。对表达式应用运算符地址,您将得到
p1
的值等于
a + 0
a
,并且
p2
的值等于表达式
a + 2
的值。

因此差值

p2 - p1
( a + 2 ) - a
相同,等于
2

来自 C 标准(6.5.6 加法运算符)

8 当整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且 数组足够大,结果指向原始元素的元素偏移量,使得结果数组元素和原始数组元素的下标之差等于整数表达式。 换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N (等效于 N+(P))和 (P)-N (其中 N 的值为 n)分别指向第 i + n 个 和 i − 数组对象的第 n 个元素,前提是它们存在。 此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素之后的一个,如果表达式 Q 指向数组对象的最后一个元素,则表达式 (Q)-1 指向数组对象的最后一个元素。如果指针操作数和结果都指向 对于同一数组对象的元素,或者超过数组对象的最后一个元素,计算不应产生溢出;否则,行为是未定义的。如果结果指向过去 数组对象的最后一个元素,不得将其用作所计算的一元 * 运算符的操作数。

注意表达式的类型是

ptrdiff_t
。所以你应该写

printf("%td",p2-p1);

而不是

printf("%d",p2-p1);
© www.soinside.com 2019 - 2024. All rights reserved.