增加内存地址如何影响指针

How does incrementing memory address affects pointer

我正在寻求有关递增地址如何影响指针的解释。

我了解了 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)

实际结果是:

2

5

为什么p好像直接指向a之后的内存?

我困惑的根源是什么?

所以在这个例子中 &a 是类型 int(*)[5]。当您将 1 添加到它时,它实际上会添加 sizeof(int[5]) - 因为这就是指针算法的工作原理,添加偏移量会将指向的类型的大小乘以偏移量。这就是你如何让 p 成为 a 的最后一个元素,之后你将它转换为 int* 所以现在你有一个指向整数的指针a 的最后一个元素。如此有效,从中减去 1 得到 a.

的最后一个元素

您可以将数组 a 作为指向 int int * 的指针进行操作。但是 &a 不一样,它是一个指向 5 个整数的数组的指针:&a + 1 会将 5 个整数的大小添加到指针。

只需在将 1 加到 a 之前删除 &,它就会按您预期的那样工作:

#include <stdio.h>

int main()
{
    int a[] = {1,2,3,4,5};
    int *p = (int*)(a+1); // & removed
    printf("%d %d\n", *(a+1), *(p-1));
    return 0;
}

两个基本概念:

  • 除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则 expression类型"N-element array of T"将被转换("decay")为类型"pointer to T"的表达式,表达式的值将是第一个地址数组的元素。

  • 向类型 "pointer to T" 的表达式加 1 会产生紧跟在当前对象之后的类型 T 的对象的地址。 IOW,如果 p 指向一个 4 字节的 intp+1 指向紧随其后的 int。如果 p 指向 int 的 5 元素数组,则 p+1 指向紧随其后的下一个 int 的 5 元素数组。这就是数组索引的工作原理——下标操作 a[i] 被定义为 *(a + i)。给定起始地址 a(指针表达式或衰减为指针的数组表达式),找到第 i 对象 的地址解决并取消引用结果。

所以,如果你有声明

int a[] = {1, 2, 3, 4, 5};

则下列说法成立:

  • 表达式 a 的类型为“int 的 5 元素数组”(int [5]) - 如果该表达式不是 sizeof 或一元 & 运算符的操作数,它 "decays" 键入 "pointer to int" (int *) 并且它的值是数组的第一个元素 (&a[0]).

  • 表达式 *(a + 1)a[1] 相同,计算结果为数组中的第二个对象 (2)。

  • 表达式 &a + 1 的类型为 int (*)[5] 并生成 a 之后 int 的 5 元素数组的起始地址。此表达式的类型转换为 int * 并分配给 p

  • 表达式 p 的类型为 int * - 从中​​减去 1 会得到 p 之前的 int 对象的地址,这发生了成为 a.

  • 的最后一个元素

图形化:

   +–––+
a: | 1 |
   +–––+
   | 2 | <–– a + 1
   +–––+
   | 3 |
   +–––+
   | 4 |
   +–––+
   | 5 | <–– p - 1
   +–––+
   | ? | <–– p (&a + 1)
   +–––+