C 对已经寻址数组基的指针应用后减量是否会调用未定义的行为?

C 对已经寻址数组基的指针应用后减量是否会调用未定义的行为?,c,arrays,pointers,C,Arrays,Pointers,在寻找与以下内容相关的或重复的问题后,没有任何结果(我只能用边际公正来描述指针算术和标记为C的减量后问题的绝对数量,但足以说明“船载”对结果集计数造成了严重的不公)我把这个扔到拳击场上,希望能得到澄清,或者找到一个我没有找到的复制品 如果将后减量运算符应用于一个指针,例如下面的数组序列的简单反向迭代,那么下面的代码是否调用未定义的行为 #include <stdio.h> #include <string.h> int main() { char s[] = "

在寻找与以下内容相关的或重复的问题后,没有任何结果(我只能用边际公正来描述指针算术和标记为C的减量后问题的绝对数量,但足以说明“船载”对结果集计数造成了严重的不公)我把这个扔到拳击场上,希望能得到澄清,或者找到一个我没有找到的复制品

如果将后减量运算符应用于一个指针,例如下面的数组序列的简单反向迭代,那么下面的代码是否调用未定义的行为

#include <stdio.h>
#include <string.h>

int main()
{
    char s[] = "some string";
    const char *t = s + strlen(s);

    while(t-->s)
        fputc(*t, stdout);
    fputc('\n', stdout);

    return 0;
}
暂时忘记了
s
有一个非零长度的字符串,这个通用算法显然有问题(可能对某些人来说没有那么清楚)。如果将
s[]
改为
,则
t
将被分配一个值
s-1
,该值本身通过其过去的一个地址不在
s
的有效范围内,并且随后对
s
进行比较的评估是不好的。如果
s
的长度不为零,则解决了初始
s-1
问题,但这只是暂时的,因为最终这仍然依赖于该值(无论它是什么)与
s
进行有效比较以终止循环。情况可能更糟。这可能是天真的:

    size_t len = strlen(s) - 1;
    char *t = s + len;
如果
s
是一个零长度的字符串,那么它就会写满灾难。用打开的这个问题的重构代码旨在解决所有这些问题。但是


我的妄想症可能会困扰我,但如果他们真的全力以赴想抓住你,那就不是妄想症。那么,根据标准(这些部分,或者其他部分),原始代码(如果您现在忘记了它是什么样子,请滚动到本小说的顶部)是否确实调用了未定义的行为?

我非常确定,在这种情况下,后减量的结果确实是未定义的行为。后减量明显地从指向对象开头的指针中减去一,因此结果不指向同一数组的元素,并且根据指针算法的定义(§6.5.6/8,如OP中所述),这是未定义的行为。从不使用结果指针这一事实与此无关

有什么问题吗

char *t = s + strlen(s);
while (t > s) fputc(*--t, stdout);


<>有趣但不相关的事实:在标准C++库中实现反向迭代器通常在反向迭代器中持有指向目标元素的指针。这使得反向迭代器可以正常使用,而不会涉及指向容器“开始前一个”的指针,即UB,如上所述。

@ShafikYaghmour请将我指给我看,它肯定会获得赞誉。如果你真的这么做了,我很抱歉没有发现。这是一个很长的问题,我必须再读一遍,但是?@ShafikYaghmour;这些答案并不令人满意。对我来说,当反向遍历数组时,
t--
指向数组最后一个元素之后的一个元素,并且是有效的。@ShafikYaghmour aww……唉,它不是。不过,这是一个很好的答案(喜欢信息量大的简洁),而且还是有一些道具。这个问题不是关于计算前一个地址或前一个地址,而是对已经加载了序列基址的指针执行后减量是否调用UB。为什么要这样做?系统的任何部分怎么可能“知道”你的
t
s
有关,或者在上一次迭代中移动到
s
以下,而你随后没有使用它?我怀疑你在这一点上确实是正确的。感谢你和沙菲克抽出时间。起初我以为(可能是酒精引起的;时间已经晚了)这样的手术是否更适合于类似陷阱的东西,但第二天早上a摆脱了这一点,现实又回到了P。再次感谢。@WhozCraig:虽然这在实践中似乎很迂腐,考虑指针是一对段+偏移量的情况。在这种情况下,
s
可能有偏移量0,递减它可能是一个陷阱,因为递减指针操作不允许在偏移量上进行环绕。哦,我完全理解为什么对这样一个“东西”的求值可能是灾难性的(您引用的情况就是这样),但是执行递减本身的行为,无论是否使用,我躲开了他。
char *t = s + strlen(s);
while (t > s) fputc(*--t, stdout);