考虑以下代码:
int main()
{
int i;
int ints[3];
ints[0] = 0;
ints[1] = 1;
ints[2] = 2;
for(i = 0; (ints[i])<4 && i<3; i++)
{
printf("%d\n", ints[i]);
}
}
有没有理由我不应该在循环中进行这种调节?我的意思是,当i
变为3
时,它会在整数[3]中查找不存在的值吗?如果是的话,可以吗?,因为循环终止了吗?它编译并运行良好,但我只是想知道是否存在某种隐藏的问题。感谢。
答案 0 :(得分:4)
在此循环的最后一次迭代中,表达式ints[i]<4
将访问ints[3]
。由于此访问读取超过数组ints
的末尾,因此行为在C中未定义。所以是的,这不是好代码。它可能在大多数情况下都有效,但行为最终未定义。
答案 1 :(得分:3)
执行i < 3 && ints[i] < 4
会更好,因为只有在第一部分为真时才会评估语句的第二部分。你拥有它的方式,它将寻找不存在的ints[3]
。
答案 2 :(得分:2)
这样做是不可行的,因为确实会访问ints[3]
。现在,因为这是C,你不会得到一个错误(不幸的是),但你永远不会知道结果会是什么。
交换语句将解决问题,因为&amp;&amp;运算符已经过优化,因此如果第一个条件为假,它就不会评估第二个条件。
答案 3 :(得分:1)
你编写循环的方式,你的代码将尝试读取不存在的数组元素int [3]。这是未定义的行为;结果是任何都可能发生。现在整个互联网都在哗然,因为OpenSSL中的一些代码调用了未定义的行为。
答案 4 :(得分:1)
'for'关键字扩展出以下方式:
int i;
for(i = 0; i < 2; i++)
dothing();
变为
int i;
i = 0; /* first part of (i = 0; ...) */
beginloop:
if (i >= 2) goto endloop; /* second part of (...; i < 2; ...) */
dothing();
i++; /* final part of (...; ...; i++) */
goto beginloop;
endloop:
因此,您的代码将扩展如下:
i = 0;
beginloop:
if (ints[i] >= 4)
goto endloop;
if (i >= 3)
goto endloop;
printf(...);
i++;
goto beginloop;
endloop:
虽然这样很好,但测试顺序存在问题:
(ints[i] < 4) && (i < 3)
在使用数组索引之前,应首先检查数组索引以确保它们有效:
i = 0:
ints[0] < 4 && 0 < 3
i = 1:
ints[1] < 4 && 1 < 3
i = 2:
ints[2] < 4 && 2 < 3
i = 3:
ints[3] < 4 && 3 < 3 /* illegal access to ints[3] */
作为一般的经验法则,除非有更好的排序理由,例如优先级,否则总是尝试按成本顺序排序条件:在这种情况下,i < 3
是两个测试中更便宜的,加上它是对您可以访问的ints
元素的约束,因此您检查索引应该具有更高的优先级 - 您应该在使用它来测试ints[i]
之前检查它。
答案 5 :(得分:1)
循环结束,没关系。但是你正在访问你所允许的范围以外的区域。这是未定义的行为。您可以随时获得细分。但你很幸运。
尝试先放i<3
。那会很好。
for(i = 0; i<3 && (ints[i])<4; i++)
如果i
变为3
,则不评估第二部分。请参阅short circuit evaluation。