2

我在 C++ 项目中发现了以下代码。代码通过 C 风格的字符串向后移动。当我看到这个时,我认为这应该导致未定义的行为。但它似乎完美地工作:

const char * hello = "Hello World.";
const char * helloPointPos = strchr(hello, '.');
for (const char * curchar = helloPointPos; *curchar; curchar--) {
  printf("%s", curchar);
}

我想知道的是*curchar; curchar--. 这假定字符串以 \0 开头。这是一个合法的假设吗?这段代码是否会导致未定义的行为?如果不是,为什么不呢?

如果您能对此有所了解,我将不胜感激。BTW平台是Windows,编译器是VC++ 2010。

编辑:谢谢大家的参与。两个答案都很好,对我有帮助。但是因为我只能接受一个答案,所以我会选择 paxdiablo 的答案,因为它有更多的细节。谢谢!

4

2 回答 2

7

不,字符串之前的字符不是必需的\0,因此代码没有定义的行为。

事实上,它是双重未定义的,因为您不允许取消引用不在数组内或超出末尾一个字节的指针。由于这是在数组之前取消引用一个字节,因此在这个意义上它也是无效的。

可能在某些情况下工作(a),但它绝不是好的代码。

无论如何,打印字符串而不是字符会给你带来奇怪的结果:

.d.ld.rld.orld.World. World.

等等。

一个更好的反向迭代器是这样的:

char *curchar = &(hello[strlen (hello)]);  // one byte beyond
while (curchar-- != hello)                 // check if reached start, post-decr
    putchar (*curchar);                    // just the character, thanks.

(a)事实上,对于未定义行为,最令人讨厌的事情之一就是它有时确实有效,让你陷入一种虚假的安全感。

我经常认为所有编码人员都应该将电线连接到他们最私密的部分,以便未定义的行为可以产生短暂的剧烈冲击 - 我怀疑一段时间后未定义的行为会少得多(或开发人员少得多): -)

于 2013-05-08T06:25:51.700 回答
4

这当然不是定义的行为,但在这种情况下,它起作用也就不足为奇了。

const char * hello = "Hello World.";将字符串Hello World.与所有其他字符串文字放在一个部分中。所以很可能,它前面有一个字符串文字,它以 结尾\0,所以\0前面有 ' Hello World.,并且代码有效。

显然你不能依赖它——你的字符串可能是该部分的第一个,或者那里可能有一些非字符串常量。此外,如果字符串以任何其他方式分配,则\0在它之前获得的机会会更低。

于 2013-05-08T06:31:57.073 回答