如何解释数组中的*(ptr)和*(ptr+2)?

How to interpret *(ptr) and *(ptr+2) in arrays?

提问人:Jackob2001 提问时间:10/15/2023 最后编辑:Vlad from MoscowJackob2001 更新时间:10/15/2023 访问量:114

问:

我不明白指针在数组中是如何工作的。

#include <stdio.h>
int main() {

  int x[5] = {1, 2, 3, 4, 5};
  int* ptr;

  // ptr is assigned the address of the third element
  ptr = &x[2]; 

  printf("value ptr = %d \n", *ptr);   // 3
  printf("address ptr = %d \n", ptr);   // 3
  printf("value ptr+2 = %d \n", *(ptr+2)); // 4
  printf("address ptr+2 = %d \n", (ptr+2)); // 4

  return 0;
}

结果:

value ptr = 3
address ptr = -1931225192
value ptr+2 = 5
address ptr+2 = -1931225184

和之间的差值是 8 个字节。 那么什么时候等于,那么为什么不等于,而是呢?ptrptr + 2ptr-1931225192ptr + 2-1931225192 + 2-1931225192 - 8

有人可以解释一下这是如何工作的吗?因为在原始值上添加 2 是合乎逻辑的,但这个 +2 变成了 -8。-1931225192

数组 C 隐式转换 指针算术

评论

1赞 tkausl 10/15/2023
why ptr + 2 isn't equal to -1931225192 + 2 but instead it is -1931225192 - 8它不是 +8(不是 -8)正是因为.+2The difference between ptr and ptr + 2 are 8 bytes.
2赞 dbush 10/15/2023
您应该使用 to 打印指针,而不是 .%p%d

答:

1赞 user16217248 10/15/2023 #1
  1. 将整数添加到指针时,不会添加固定数量的字节。您正在添加固定数量的元素。这意味着您正在隐式添加字节。为了避免这种情况,如果你想严格地添加一些字节,你可以将数组转换为 a。n*sizeof(int)char *

    可以这样想:由于 访问给定的元素并被定义为等价于 ,我们看到没有 简单地获取 的地址。ptr[n]*(ptr + n)(ptr + n)*ptr[n]

  2. 转换为整数的地址似乎是负数,因此添加正值会减小其大小。因此,更改为 not a .+2+8-8

评论

0赞 Jackob2001 10/15/2023
对于数字 2。我大错特错了,不是 -8,而是 +8。对于数字 1。所以在这种情况下,它与 ptr + n*sizeof(int) 相同 ptr+2*sizeof(int) ?这很奇怪,我认为它与直觉相符,例如 ptr + 2 而不是 ptr 2*sizeof(int)。很高兴知道。
0赞 user16217248 10/15/2023
@Jackob2001是的。指针算术带有隐式 .*sizeof(*ptr)
0赞 Jackob2001 10/15/2023
我还有一个问题。那么,如果假设 -1931225192 包含值 3,那么 -1931225191 包含什么?我可以添加 -1931225191 不同的值吗?
0赞 user16217248 10/15/2023
@Jackob2001 未定义的行为。如果尝试访问的地址不是该类型的对齐要求的倍数,则行为是未定义的,并且结果是不确定的。通常为 4 个字节,并且还具有 4 个字节的对齐方式,因此,如果您尝试访问的指针不是 4 的倍数,则可能会出现问题。intint
0赞 Jackob2001 10/15/2023
我还有一个问题,这是最后一个问题,因为我现在想出了它。如果我写 *(ptr + 2*sizeof(int)) 会发生什么?那么它会是 *(ptr + (2*sizeof(int))*sizeof(int)) 吗?我想说的是,我想用 2*sizeof(int) 代替 +2 而不是 *(ptr + 2)(因为正如你所说,这个 2 是更改为 2*sizeof(int))它会是一样的还是会改变?
0赞 Vlad from Moscow 10/15/2023 #2

首先,这两个电话printf

printf("adress ptr = %d \n", ptr);   // 3
printf("adress ptr+2 = %d \n", (ptr+2)); // 4

具有未定义的行为,因为使用了为整数设计的不正确的转换说明符来输出指针。你需要写d

printf("adress ptr = %p \n", ( void * )ptr);   // 3
printf("adress ptr+2 = %p \n", ( void * )(ptr+2)); // 4

完成此任务后

ptr = &x[2]; 

指针指向数组的元素。因此,像您一样取消引用指针将获得其值等于 的元素。ptrx[2]x*ptrx[2]3

您可以通过以下方式重写上述作业

ptr = x + 2; 

表达式指向数组中第二个元素,该元素位于该元素之后。取消引用表达式,您将得到其值等于 的元素。ptr + 2xx[2]x[4]*( ptr + 2 )x[4]5

指针表达式 的值之差等于 。ptrptr + 22 * sizeof( int )

由于您使用不正确的转换说明符来输出指针,因此您的负数为

adress ptr = -1931225192

and

adress ptr+2 = -1931225184

这些数字之间的差值等于 。如上所述,您需要使用 cirrect 转换说明符来输出指针表达式的有效值。2 * sizeof( int )p

通常,如果您有一个数组,例如,有一个由数组第一个元素的地址初始化的指针,例如xptrx

int x[5] = {1, 2, 3, 4, 5};
int* ptr = x;

然后表达式指向数组的元素。这就是所谓的指针算术。指向某个数组元素的两个点的差值等于指针指向的元素之间的元素数。ptr + ii-thx

在本声明中

int* ptr = x;

数组指示符隐式转换为指向其第一个元素的指针。这个声明实际上等价于x

int* ptr = &x[0];