【问题标题】:Why does pointer subtraction in C yield an integer?为什么C中的指针减法会产生整数?
【发布时间】:2016-01-22 20:42:00
【问题描述】:

为什么如果我从一个指针中减去另一个指针(整数指针)而不进行类型转换,结果将是 1 而不是 4 个字节(就像我将两个指针都类型转换为 int 时一样)。示例:

int a , b , *p , *q;
p = &b;
q = p + 1; // q = &a;
printf("%d",q - p); // The result will be one .
printf("%d",(int)q - (int)p); // The result will be 4(bytes). The memory address of b minus The memory address of a.

【问题讨论】:

  • 您的代码调用了未定义的行为。对于指针差异,请使用 ptrdiff_t 和适当的说明符到 printf
  • 正常的,当你做pointer = pointer + 1时,它增加了1 * sizeof(int *);
  • @PierreEmmanuelLallemant:我相信你的意思是1 * sizeof(int),而不是int*
  • 因为指针算法旨在匹配数组索引。换句话说,array[i] 等价于*(array + i)
  • 这是一个很好的解释。 @user3386109

标签: c pointers


【解决方案1】:

根据 C 标准(6.5.6 加法运算符)

9 当两个指针相减时,都应该指向 相同的数组对象,或超过数组的最后一个元素 目的;结果是两者下标的差 数组元素....

如果两个指针指向同一个数组的元素,那么正如标准引用中所说的那样

结果是两个数组的下标之差 元素

也就是说,您将获得这两个指针之间的数组元素数。就是所谓的指针运算的结果。

如果您将存储在指针中的地址作为整数值相减,那么您将得到与算术减法运算相对应的数字。

【讨论】:

  • 所以qp之间的减法返回'q'和'p'之间的'距离'。如果 p 指向数组的第一个元素,q 指向最后一个元素。 q - p 返回数组元素个数?
  • @Călin Calin,您不会将 int 数组索引为 array[0]... array[4]... array[8]... 以考虑数据大小吗?它与指针算法相同。
  • 您在粗体文本之后立即忽略了“或超过最后一个元素”。 q - p 有效。 (但使用了错误的格式说明符)。
  • @CălinCalin 如果第一个指针指向第一个元素,第二个指针指向最后一个元素之后的元素,那么它们的差就是数组中元素的数量。另一方面,如果您将两个指针都转换为 char * 类型,那么差异将以字节为单位给出数组的大小,因为 sizeof(char) 始终等于 q。也就是说,如果您将数组视为字符数组,则数组的元素数等于数组的大小(以字节为单位)。
  • @CălinCalin 与表达式 (q - p) * sizeof(int) 相同。
【解决方案2】:

为什么如果我从一个指针中减去另一个指针(整数指针)而不进行类型转换,结果将是 1 而不是 4 个字节

这就是指针指向的数据类型的全部意义。查看如下所示的数组上下文可能更容易。关键是无论底层数据类型(此处为longdouble),您都可以使用指针算法来导航数组,而无需关心其元素的大小。换句话说,(pointer + 1) 表示指向下一个元素,无论类型如何。

long l[] = { 10e4, 10e5, 10e6 };
long *pl = l + 1;    // point to the 2nd element in the "long" array.

double d[] = { 10e7, 10e8, 10e9 };
double *pd = d + 2;    // point to the 3rd element in the "double" array.

还要在您的代码中注明:

int a , b , *p , *q;
p = &b;
q = p + 1; // q = &a;   <--- NO this is wrong. 

ab声明 相邻并不意味着ab分配 相邻在记忆中。所以q 指向b 旁边的内存地址 - 但该地址中的内容是未定义的。

【讨论】:

  • 指向一个未初始化的区域很好,也很常见。这可能在*q = 7 之前初始化内存(变量)。
  • 但绝对不是这段代码中a的地址。
  • 也许不是a,我同意期望它是非常不明智的。
【解决方案3】:

因为ptrdiff_t from 指针减法是相对于所指向元素的大小计算的。这样方便多了;一方面,它告诉你在到达另一个指针之前你可以增加一个指针多少次。

【讨论】:

    【解决方案4】:

    你在哪里

    int a , b , *p , *q;
    

    编译器可以将ab 放在任何地方。他们甚至不必彼此靠近。此外,当您减去两个int 指针时,结果的大小是int,而不是字节。

    【讨论】:

      【解决方案5】:

      C 不是汇编语言。所以指针不仅仅是简单的整数——指针是知道如何指向其他事物的特殊人。

      指针和指针算术在 C 中的工作方式的基础是它们可以指向数组的连续元素。所以如果我们写

      int a[10];
      int *p1 = &a[4];
      int *p2 = &a[3];
      

      那么p1 - p2 将为1。结果为1,因为a[3]a[4] 之间的“距离”为1。结果是 1,因为 4 - 3 = 1。结果是 not 4(如果您知道 ints 在您的机器上是 32 位,您可能会认为它会是这样),因为我们'对汇编语言编程或使用机器地址不感兴趣;我们正在使用数组进行高级语言编程,并且我们正在考虑这些术语。

      (但是,是的,在机器地址级别,p2 - p1 的计算方式通常为(p2 中的原始地址值> - p1> 中的原始地址值)/sizeof(int)。 )

      【讨论】:

        猜你喜欢
        • 2016-01-22
        • 2012-03-11
        • 2011-11-18
        • 2018-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多