【问题标题】:Why is pointing one position beyond a valid object acceptable for pointers?为什么指针可以指向超出有效对象的一个​​位置?
【发布时间】:2020-07-23 12:51:42
【问题描述】:

在 Jens Gustedt 的教科书“Modern C”中,我读到了“指针必须指向有效对象或超出有效对象的一个​​位置或为空。”的指针。为什么指向有效对象之外的一个位置是可以接受的?例如:

int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location
p = array + 6 // points to an invalid location

【问题讨论】:

  • 请引用教科书。我想读一读。
  • p = array + 5 // points to a valid location -- 不,它没有!
  • 当迭代一个数组并后递增一个指针时,它允许最后一个元素被视为与其他元素相同,而无需对其进行特殊处理。指向一个超越,并不意味着它可以被取消引用。
  • @RobertSsupportsMonicaCellio:您指向的评论并没有这么说。该注释是在 p_a 指向结构成员而不是数组的上下文中,因此未定义 p_a+4。这与数组中的指针运算和最后一个元素之外的位置无关。
  • 是的,@RobertSsupportsMonicaCellio。因此,对于任何左值x,都可以评估&x + 1,存储结果,并以多种方式使用它。这算作指向数组末尾后一个元素的指针。但对于许多——虽然不是全部——左值,计算&x + 2&x + 3。有未定义的行为,你和 M.M.正在讨论其中一个案例。

标签: c pointers


【解决方案1】:

支持“一个超越最后一个”使处理数组更简单。例如,如果使用指向某个元素的指针 Start 调用函数,它可能需要准备结束指针 End 并使用如下循环:

for (ElementType *p = Start; p < End; ++p)

为此,End 必须是一个有效的指针。

我们可能会考虑将End 设置为要处理的最后一个元素,而不是超出它的一个元素,并使用:

for (ElementType *p = Start; p <= End; ++p)

但是,请注意,在处理完最终元素后,p 将递增到超越 End。然后,为了使p &lt;= End 成为一个有效的表达式,p 必须是一个有效的指针。因此,我们需要能够在数组的最后一个元素之外进行地址算术运算。

【讨论】:

  • 感谢您的回答,通过指针分配给位置“超出有效对象的一个​​位置”仍然被认为是无效的,对吧?
  • @Alex:是的,指针是有效的(它的值可以用于指针比较和算术),但是尝试访问(读取或写入)指针指向的内容不是由 C 定义的标准。
【解决方案2】:

您的代码 cmets 表达了可能的误解。与...

int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location

...p指向一个有效的位置。对array + 5 求值是允许且定义明确的,这会产生p 可以存储的值,但任何取消引用该指针值的尝试都会导致未定义的行为。

p 的此类值有时可用作array 元素地址的排他上限,或用于向后索引array(严格为负索引),但您不能尝试访问价值本身。

相比之下,在这种情况下...

p = array + 6 // points to an invalid location

...p 不指向任何东西,至少可以通过分析代码确定。尝试计算表达式 array + 6 会产生未定义的行为,尤其是结果定义不明确。

【讨论】:

  • 重新“指向一个有效的位置”:这里的术语有些松懈。 C 标准没有定义这个短语。可以使用“指向有效位置”来表示指针值已明确定义,但并不表示可以访问该位置的对象。
  • 我不倾向于争论这一点,@EricPostpischil。我在此答案中关于和使用该短语的评论旨在解释 OP 对它的使用,并在上下文中反驳我认为它们最可能的含义。它们实际上可能意味着不同的东西,在这种情况下,我认为他们和我之间的含义差异会从上下文中清楚地显示出来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 2021-11-11
  • 1970-01-01
  • 2015-02-16
  • 2018-04-03
  • 1970-01-01
相关资源
最近更新 更多