【发布时间】:2012-07-23 22:53:43
【问题描述】:
考虑 C 中的一个循环,它在循环体中声明一个字符数组。在每次迭代中,数组的一个字符都会被修改,直到到达末尾。最后,打印变量。描述将扩展到下一个代码:
#include <stdio.h>
int main(void) {
int i = 0;
for (;;) {/* same as: while(1) { */
char x[5];
x[i] = '0' + i;
if (++i == 4) {
x[i] = '\0'; /* terminate string with null byte */
printf("%s\n", x);
break;
}
}
return 0;
许多人可能期望0123 作为输出。但由于某种原因,GCC 4.7 在启用优化(-O1 和更高版本)进行编译时不会这样做。而是将随机数据放在字符数组的第一个字节中,变为:
| 0 | 1 | 2 | 3 | 4 |
| RANDOM | '3' | '\0' |
我认为从语言的角度来看这是合乎逻辑的行为:块终止后自动变量消失了,因此应该预料到上述“随机”行为。
正确的行为应该是什么? 我知道将x 的声明移到循环之外“修复”它,但这并没有说明这个sn-p 的行为。现实世界的问题是bug in Netfilter。
【问题讨论】:
-
x[i] = '0' + i;当循环第一次运行时,这一行会发生什么?因为此时 i = 0 并且执行的等效行是 x[0] = '0' + 0。所以我们想将 00 存储在 x[0] 中。我很久以前读过 C,所以不记得字符数组是如何工作的。你能解释一下吗?
-
@Rain
'0' + 0只是'0','0' + 2是'2',那部分很好。由于范围有问题,只是数组的未指定内容。 -
感谢您的澄清。那么很明显,我们将为第一个 3 个字符设置随机值,因为在最后一次迭代中,将执行的等效行是 x[3] = 3,我们没有为 x[0]、x[1] 和 x[ 2]。因此,我们将始终如您在问题中所说的那样得到结果。
-
@Rain 邪恶的部分是结果很可能确实是一个数组
{ '0', '1', '2', '3', '\0' }打印。编译器在每次迭代时将数组放在同一个位置是很自然的,既然它没有初始化,为什么它不应该包含之前迭代中写入的数据呢?我为所有优化级别打印了 0123。 -
:) 是的,由于编译器的帮助,您正在获得输出。但是当我们不分配任何值时,我们应该得到垃圾。但正确的做法是在循环外声明数组。
标签: c loops scope variable-declaration