【问题标题】:Different results when using increment operator (arr[i++] vs arr[i]; i++;)使用增量运算符时的不同结果(arr[i++] vs arr[i]; i++;)
【发布时间】:2021-01-26 13:48:29
【问题描述】:

我不明白为什么下面的代码没有按预期工作:

#include <stdio.h>

int main() {
    int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
    while (i < size && oneOrZero[i++]);
    if (i == size) printf("All ones"); else printf("Has a zero");
}
Terminal: All ones.

当增加循环内的索引使代码按预期运行时:

#include <stdio.h>

int main() {
    int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
    while (i < size && oneOrZero[i]) {i++;}
    if (i == size) printf("All ones"); else printf("Has a zero");
}
Terminal: Has a zero.

有人能解释一下这两者的区别吗?

【问题讨论】:

  • 仔细阅读&amp;&amp; 运算符的文档。如果左侧表达式为 0,则根本不会计算右侧表达式。阅读this, andd/or google c operator short circuit
  • 正如@Jabberwocky 已经说过的 && 和 ||评估已优化,因此如果第一个条件为 False (0),则不需要评估第二个条件,因为无论如何整体都是 False (0)。当第一个条件为 || 上的 True (1) 时,也会发生类似的事情。操作员。当你 i++ 处于第二个条件时,它并不总是像在 while 块上那样被评估。
  • 正如@pmg 所说,当 i 的值为 8 时, oneOrZero[i] 返回 0 但是,在循环结束之前, i 递增,所以在下一个测试中 i 值为 9
  • @pmg 评论正确,这与操作员短路无关。
  • 故事的寓意:number_of_bugs_caused_by_post_increment++;。具有讽刺意味。

标签: c increment postfix-operator


【解决方案1】:

在第一个代码中,当i8 时,oneOrZero[i] 将评估为false,因为oneOrZero[8] == 0,但无论如何i 将递增到9,增量不依赖于表达式的truthiness,它会随着表达式的计算而发生多次。

所以很自然地,当评估 i == size 时,它是 9 == 9,当然这是 true,因此将打印 "All ones",给你错误的输出。

在第二个代码中i在条件表达式的主体内递增,这意味着它只有在满足条件时才会递增,所以当i8时,oneOrZero[i]将评估为@ 987654339@ 和 i 不递增,保留其 8 值。

在下一行语句中,i == size 将是 8 == 9,即 false"Has a zero" 将被打印出来,为您提供正确的输出。

【讨论】:

    【解决方案2】:

    当使用迭代索引i 进行检查时,这是一个典型的逐一错误(与size 比较)。不用担心,几乎每个人都会遇到这种情况。

    问题是,即使条件失败,我们已经在oneOrZero[i++] 中更改了结果(i)。我们的第二个变体不会落入这个陷阱,因为条件和索引增量是解耦的。

    我们可以用一个更简单的例子来复制这种行为:

    #include <stdio.h>
    
    int main() {
        int i = 0, size = 1, oneOrZero[] = {0};
        while (i < size && oneOrZero[i++]);
        if (i == size) printf("All ones"); else printf("Has a zero");
    }
    

    现在,让我们手动检查一下条件:

    1. i &lt; size 很好,所以我们继续评估右侧。
    2. i++ 增量 i1(又名size
    3. oneOrZero[0]0,因此条件不成立

    在这一次迭代之后,i == size,我们打印All ones


    将此与其他变体进行比较:

    int main() {
        int i = 0, size = 1, oneOrZero[] = {0};
        while (i < size && oneOrZero[i]) {i++;}
        if (i == size) printf("All ones"); else printf("Has a zero");
    }
    

    我们再次检查条件:

    1. i &lt; size 很好
    2. oneOrZero[0] == 0,所以我们停下来。
    3. i 永远不会增加

    因此i &lt; size,我们打印Has a zero


    请注意,可以将条件更改为

    int i = -1;
    
    while(++i < size && oneOrZero[i]);
    

    但这需要仔细记录。

    【讨论】:

      【解决方案3】:
         #include <stdio.h>
              
              int main() {
                  int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
                  while (i < size && oneOrZero[i++]);
                  if (i == size) printf("All ones"); else printf("Has a zero");
              }
      

      上面的代码一直执行到i = 8,第一个条件i &lt; size8 &lt; 9,但第二个条件oneOrZero[8]false。无论如何我都会增加到 9。9 == 9 所以它会打印"All ones" 会打印给你错误的输出。

      #include <stdio.h>
      
      int main() {
          int i = 0, size = 9, oneOrZero[] = {1,1,1,1,1,1,1,1,0};
          while (i < size && oneOrZero[i]) {i++;}
          if (i == size) printf("All ones"); else printf("Has a zero");
      }
      

      上面的代码执行到i = 8 并计算为i &lt; size8 &lt; 9oneOrZero[i] oneOrZero[8] = 0 并计算为false 并退出循环 和 i == size 8 == 9 和 prints Has a zero 将被打印出来,给你正确的输出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-31
        • 1970-01-01
        • 1970-01-01
        • 2021-09-10
        • 2012-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多