for循环中的条件检查

时间:2014-04-12 20:57:46

标签: c for-loop conditional-statements

考虑以下代码:

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]中查找不存在的值吗?如果是的话,可以吗?,因为循环终止了吗?它编译并运行良好,但我只是想知道是否存在某种隐藏的问题。感谢。

6 个答案:

答案 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