【问题标题】:Different Pointer Arithmetic Results when Taking Address of Array取数组地址时指针运算结果不同
【发布时间】:2016-02-19 22:21:23
【问题描述】:

程序:

#include<stdio.h>

int main(void) {
    int x[4];
    printf("%p\n", x);
    printf("%p\n", x + 1);
    printf("%p\n", &x);
    printf("%p\n", &x + 1);
}

输出:

$ ./a.out
0xbff93510
0xbff93514
0xbff93510
0xbff93520
$

我希望以下是上述程序的输出。例如:

x        // 0x100
x+1      // 0x104  Because x is an integer array
&x       // 0x100  Address of array
&x+1     // 0x104

但最后一条语句的输出与我预期的不同。 &amp;x 也是数组的地址。所以在这个上加 1 将打印增加 4 的地址。但&amp;x+1 给出的地址增加了 10。为什么?

【问题讨论】:

  • 看来 &x+1 给了你数组内存后的地址(4*4=16 or 0x100)...
  • 这是您清楚地看到指针和数组之间区别的情况之一。
  • 重要说明:这些地址是十六进制的。 “递增 4”也表示 0x4 递增,但 递增 0x10”表示“递增 16”,而不是到 10 点。
  • @LukePark 实际上应该是 int (*)[4] 类型
  • 只是一个注释(与您所问的问题无关):您的程序具有未定义的行为(至少在 C99 下),因为您需要在将指针传递给 void * 之前将它们转换为 @987654328 @(因为它是一个可变参数函数)。见Printing pointers in C

标签: c pointers language-lawyer


【解决方案1】:
x -> Points to the first element of the array.
&x ->Points to the entire array.

在这里偶然发现了一个描述性的解释:http://arjunsreedharan.org/post/69303442896/the-difference-between-arr-and-arr-how-to-find

链接:Why is arr and &arr the same?

【讨论】:

    【解决方案2】:

    如果是 4,您会得到 0x100 + sizeof xsizeof x 是 4 * sizeof int = 4 * 4 = 16 = 0x10。

    (在您的系统上,sizeof int 是 4)。

    【讨论】:

    • 添加了 sizeof int 步骤,因为它因系统而异。
    【解决方案3】:

    一个简单的评估规则是:

    increment 上的任何指针都指向其基本类型的下一个内存位置。

    这里 &x 的基本类型是 int (*p)[4],它是一个指向 4 个整数数组的指针

    所以这种类型的 next 指针将指向距离原始数组 16 个字节(假设 int 为 4 个字节)。

    【讨论】:

      【解决方案4】:

      尽管x&amp;x 计算为相同的指针值,但它们是不同的类型。 x 衰减为指针后的类型为int*,而&amp;x 的类型为int (*)[4]

      sizeof(x)sizeof(int)*4

      因此&amp;x&amp;x + 1 之间的数值差为sizeof(int)*4

      使用二维数组可以更好地可视化。假设您有:

      int array[2][4];
      

      array 的内存布局为:

      array
      |
      +---+---+---+---+---+---+---+---+
      |   |   |   |   |   |   |   |   |
      +---+---+---+---+---+---+---+---+
      
      array[0]        array[1]
      |               |
      +---+---+---+---+---+---+---+---+
      |   |   |   |   |   |   |   |   |
      +---+---+---+---+---+---+---+---+
      

      如果你使用指向这样一个数组的指针,

      int (*ptr)[4] = array;
      

      并通过指针查看内存,是这样的:

      ptr             ptr+1
      |               |
      +---+---+---+---+---+---+---+---+
      |   |   |   |   |   |   |   |   |
      +---+---+---+---+---+---+---+---+
      

      如您所见,ptrptr+1 之间的区别是sizeof(int)*4。这个类比适用于代码中&amp;x&amp;x + 1 之间的区别。

      【讨论】:

        【解决方案5】:

        信不信由你,你的程序的行为是未定义

        &amp;x + 1 实际上指向数组之外的 just,正如@i486 的回答巧妙地指出的那样。你不拥有那段记忆。即使尝试分配一个指向它的指针也是未定义的行为,更不用说尝试取消引用它了。

        【讨论】:

        • 我一直认为这是定义的,因为定义了一个指向数组末尾的指针。我想这可能会有所不同,因为这不是int[4]s 的数组,它只是一个。
        • @Bathsheba:你能在这里引用标准吗?通常,结束指针之后是定义明确的东西;为什么不应该在这种特殊情况下?
        • @Bathsheba:正如 Hurkyl 所提到的,标准中应该有一个关于“标量”对象如何被视为大小为 1 的数组以用于“过去”指针的说明。我希望这在这种情况下能够成立(因为数组可以包含数组),但标准经常违背我的期望。
        • @Bathsheba 您不允许“查看”数组之外的内容,但 IIRC 明确允许您将该地址存储在指针中。我认为this answer(以及该问题的其他人)涵盖了这一点。
        • @Bathsheba C11 6.5.6 p7:“指向不是数组元素的对象的指针与指向长度为 1 的数组的第一个元素的指针的行为相同”。甚至没有注释——这是正文。 (紧接在关于one-past-the-end 的内容之前)这里没有 UB。 标量与用于指针算术目的的数组完全相同。
        猜你喜欢
        • 2014-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-06
        • 2010-09-20
        相关资源
        最近更新 更多