C/C : 指针算术

新手上路,请多包涵

我在 Pointer Arithmetic 中读了一点,我遇到了两件我无法理解的事情,也不知道它的用途

address_expression - address_expression

并且

address_expression > address_expression

有人可以向我解释一下它们是如何工作的以及何时使用它们。

编辑:

我的意思是,如果我只取两个地址并减去它们,它们会产生什么

如果我取两个地址并比较它们,结果是什么或比较基于

编辑:我现在了解减去地址的结果,但比较地址我仍然不明白。

我知道 1,但是一个地址如何大于另一个地址以及它们的比较对象是什么

原文由 Mohamed Ahmed Nabil 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 586
2 个回答

指针减法产生相同类型的两个指针之间的数组元素数。

例如,

 int buf[10] = /* initializer here */;

&buf[10] - &buf[0];  // yields 10, the difference is 10 elements

指针比较。例如,对于 > 关系运算符: > 运算产生 1 如果左侧的指向数组元素或结构成员在指向后右侧的元素或结构成员,否则产生 0 。请记住,数组和结构是有序序列。

  &buf[10] > &buf[0];  // 1, &buf[10] element is after &buf[0] element

原文由 ouah 发布,翻译遵循 CC BY-SA 3.0 许可协议

这里有几个答案表明指针是数字。这不是 C 标准指定的指针的准确描述。

在很大程度上,您可以将指针视为数字和内存中的地址,前提是(a)您了解指针减法将差异从字节转换为元素(被减去的指针的类型),并且(b)您了解此模型打破的限制。

以下使用 1999 C 标准 (ISO/IEC 9899, Second edition, 1999-12-01)。我希望以下内容比提问者要求的更详细,但是,鉴于这里的一些错误陈述,我认为应该提供准确和准确的信息。

根据 6.5.6 第 9 段,您可以减去两个指向同一数组元素的指针或指向数组最后一个元素的指针。 So, if you have int a[8], b[4]; , you may subtract a pointer to a[5] from a pointer to a[2] , because a[5] and a[2] 是同一个数组中的元素。您也可以从指向 --- 的指针中减去指向 a[5] a[8] 指针,因为 a[8] 是数组的最后一个元素。 ( a[8] is not in the array; a[7] is the last element.) You may not subtract a pointer to a[5] from a pointer to b[2] ,因为 a[5] b[2] 同一个数组中。或者,更准确地说,如果你做这样的减法,行为是不确定的。请注意,未指定的不仅仅是结果;你不能期望你会得到一些可能是荒谬的数字: 行为 未定义。根据 C 标准,这意味着 C 标准没有说明任何结果。你的程序可以给你一个合理的答案,或者它可以中止,或者它可以删除文件,所有这些结果都将符合 C 标准。

如果您执行允许的减法,则结果是从第二个指向元素到第一个指向元素的元素数。因此, a[5]-a[2] 是 3,而 a[2]-a[5] 是 -3。无论 a 是什么类型,这都是正确的。需要 C 实现将字节(或它使用的任何单位)的距离转换为适当类型的元素。如果 adouble 的数组,每个 8 个字节,那么 a[5]-a[2] 是 3,对于 3 个元素。如果 achar 每个字节的数组,则 a[5]-a[2] 是 3,对于 3 个元素。

为什么指针永远不仅仅是数字?在某些计算机上,尤其是较旧的计算机上,寻址内存更为复杂。早期计算机的地址空间很小。当制造商想要制造更大的地址空间时,他们也想保持与旧软件的一些兼容性。由于硬件限制,他们还必须实施各种寻址内存的方案,这些方案可能涉及在内存和磁盘之间移动数据或更改处理器中控制如何将地址转换为物理内存位置的特殊寄存器。对于在这样的机器上工作的指针,它们必须包含更多的信息,而不仅仅是一个简单的地址。因此,C 标准不仅仅将指针定义为地址,还允许您对地址进行算术运算。仅定义了合理数量的指针算术,并且需要 C 实现提供必要的操作以使该算术工作,但仅此而已。

即使在现代机器上,也可能存在并发症。在 Digital 的 Alpha 处理器上,指向函数的指针不包含函数的地址。它是函数描述符的地址。该描述符包含函数的地址,并且它包含一些正确调用函数所必需的附加信息。

关于关系运算符,例如 > ,C 标准在 6.5.8 第 5 段中说,您可以比较可以减去的相同指针,如上所述,您还可以比较指向聚合对象(结构或联合)的成员。指向数组成员(或其结束地址)的指针以预期的方式进行比较:指向较高索引元素的指针大于指向较低索引元素的指针。指向同一个联合的两个成员的指针比较相等。对于指向结构的两个成员的指针,指向后面声明的成员的指针大于指向前面声明的成员的指针。

只要您保持在上述约束范围内,您就可以将指针视为内存地址的数字。

通常,C 实现很容易提供 C 标准所要求的行为。即使计算机具有复合指针方案,例如基地址和偏移量,通常数组的所有元素都将使用彼此相同的基地址,而结构的所有元素将使用彼此相同的基地址。因此编译器可以简单地减去或比较指针的偏移部分以获得所需的差异或比较。

但是,如果你在这样的计算机上减去指向不同数组的指针,你会得到奇怪的结果。由基地址和偏移量形成的位模式可能看起来比另一个指针更大(当解释为单个整数时),即使它指向内存中的较低地址。这是您必须遵守 C 标准设定的规则的原因之一。

原文由 Eric Postpischil 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏