【问题标题】:Combined assignment operator in a while loop condition in CC中while循环条件中的组合赋值运算符
【发布时间】:2022-02-02 10:46:27
【问题描述】:

我真的很难理解以下代码是如何工作的:

int x = -2;

while ( --x > -10 && (x -= 2)) {
    printf ( " %d," , x ) ;
}
printf ( " %d" , x ) ;

output:   -5, -8, -11, -12

我的意思是我得到了什么

while ( --x > -10)

output:  -3, -4, -5, -6, -7, -8, -9, -10

while (x -= 2)

output: -> infinte loop

单独可以,但是它们如何与 and 运算符一起使用? 我的意思是对于“while (x -= 2)”,只有当 x = 2 时才满足条件,所以 while 循环如何才能结束而不是像只使用“while (x -= 2)”时那样无限循环?

【问题讨论】:

  • how can the while loop even end and not go infinite - 这正是 && 运算符在原始循环中处理的内容。两个表达式都必须为真才能使循环继续。当其中任何一个为假时,循环终止。
  • -2-2 = -4 非零,因此 while 循环无限运行。事实上,对于任何正奇数或任何负数,它都应该无限运行。
  • "只有当 x = 2 时才满足条件":这是唯一满足条件的情况。
  • @kiner_shah:x == 2 并非如此(这是问题底部所述的值)。
  • @bbbbbbbbbb,是的,我提到了正奇数。 x == 2 绝对不是奇数。

标签: c while-loop infinite-loop logical-operators assignment-operator


【解决方案1】:

你以 -5 开头的事实非常明显:

int x = -2;
while ( --x > -10 && (x -= 2)) {

--xx 从 -2 变为 -3。
x -= 2x 从 -3 变为 -5。

... 所以它更进一步:使用 --xx -= 2 再次递减 3,所以你得到像 -8 和 -11 这样的值。 (当您达到 -11 时,您已经检查了“> -10”,当时是 -9)

然后,您再次执行--x,将-11 变为-12,但您跳出while 循环并再次打印该新值。

编辑,更多说明:

x -= 2 表示x=x - 2,这不是某种检查。

【讨论】:

  • 那么对于 x 的值是多少,x -= 2 是真的?对我来说,如果它仅在x = 2 时为真,我会说得通。但正如评论中提到的,这是唯一不正确的情况。但这对我来说毫无意义..?
  • 对编辑的回应:所以这意味着x -= 2 没有给出一个布尔值,这个布尔值必须为真才能让while循环继续?仅当检查 while 条件完成时才影响 x 的值?那么如果是这样的话,while循环条件中的操作是按什么顺序执行的呢?从左到右还是反之?我似乎首先完成了对 x 的所有操作,然后使用“新”x 的值进行检查 x > -10
  • 或者换个方式问:为什么int x = 10; while ( --x > -16 && (x -= 5))x = 21的最终值?当 x 达到 20 时,不满足 while 循环的条件,但仍会执行 --x,但不会执行 x -= 5。所以我不明白为什么会这样?
  • @riko 它总是评估为真。 && 的目的是不在循环的最后一圈执行/评估正确的操作数,仅此而已。类似地,我们可以将 if 语句替换为 x > -10 && foo(); 之类的东西,相当于 if(x > -10) foo();
  • 这里的诀窍是 C 有 短路评估 - 如果第一项为假,则不评估第二项。
【解决方案2】:

代码被不必要地混淆了......

你说得对,while ( x -= 2 ) 会导致无限循环。

但是,C 具有(所谓的)短路运算符

因此,在表达式while ( --x > -10 && (x -= 2) ) 中,仅当第一项为真时才计算第二项。

因此,虽然第一项 --x > -10 成立,但第二项 (x -= 2) 也被评估...一旦第一项变为假,第二项就不会被评估,并且循环仅以单个 pre 退出-decrement... 导致您观察到的输出。

【讨论】:

    【解决方案3】:

    测试被故意混淆。步骤如下:

    • --x > -10 总是递减 x 并将结果值与 -10 进行比较,如果 x 达到 -10 或更低,则退出循环。
    • 如果 x >= -10 来自先前的测试,(x -= 2) 进一步将 x 的值减少 2 并测试结果值是否非零。 x 的唯一值(x -= 2) 为零是x = 2。在本例中,x 始终为负,因此该测试始终为真。

    x = -2开始,迭代为:

    • --x -> x = -3,比较为真
      (x -= 2) -> x = -5, printf 输出-5

    • --x -> x = -6,比较为真
      (x -= 2) -> x = -8, printf 输出-8

    • --x -> x = -9,比较为真
      (x -= 2) -> x = -11, printf 输出-11

    • --x -> x = -12,比较为假,退出循环

    • 最终的printf 输出-12

    【讨论】:

      【解决方案4】:

      代码:

      int x = -2;
      
      while ( --x > -10 && (x -= 2)) {
          printf ( " %d," , x ) ;
      }
      printf ( " %d" , x ) ;  
      

      让我们干运行代码并在循环运行时检查 x 的值。现在,循环有两个条件要满足,即 --x > -10 && (x -= 2)。在第一个条件下,首先减小值,然后检查条件,即 (x = x - 1) > -10。第二个条件总是减少 2,即 x = x - 2,因此总是为真。直到两个条件都为真,循环将继续。据我所知,第二部分永远是真实的。 x的初始值=-2,

       Value of x                 Output
      

      In the first loop:
      is --x > -10, (x -= 2)
         True      True
         x = -3, x = -5                 -5
      In the sec loop:
      is --x > -10, (x -= 2)
         True      True
         x = -6, x = -8                 -8
      In the third loop:
      is --x > -10, (x -= 2)
         True      True
         x = -9, x = -11                -11
      In the fourth loop -> exits the while loop since x > -10:
      is --x > -10, (x -= 2)
         False      True
         x = -12, x = -14              -12
      

      【讨论】:

      • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
      【解决方案5】:

      这是一些“混淆视听”的算法,除了“不要写这样的废话”之外,可以从中学到很少的价值。

      它所做的是将值减少 3,但将减少分成两步。首先总是减少 1,然后再减少 2,除非它是循环中的最后一圈。因此&& 有两个目的:在最后一次迭代中仅减少 1,以及允许在同一表达式中对x 进行两次修改的序列点(这是非常糟糕的做法,&& 或不是)。

      对于那些不参加国际混淆 C 代码竞赛的人来说,重写类似这样的代码可能更有意义:

      int x;
      for(x = -5; x >= -11; x -= 3)
      {
        printf("%d, ", x);
      }
      printf("%d", x+2);
      

      这也是无意义的代码,但至少它是可读的。作为奖励,它还包含比混淆版本更少的分支。

      【讨论】:

      • 我完全同意你的看法,这是无意义的代码,但它是我在工程学校(机械工程)参加的考试的代码。因此问题。并感谢您的明确回答!
      • @riko 听起来像是那种只会让工程师远离软件的编程课程。我可能在想一些事情,但似乎很常见的是,与那些不专门学习计算机工程的人相比,那些不专门学习计算机工程的人上的 C 初学者课程比那些学习的人更差。
      • 如果新员工不知道这段代码做了什么,你想让他们处理生产代码吗?
      • @EricPostpischil 如果一家公司在面试问题上向我展示了这样的内容,我愿意在该公司工作吗?
      • 这样的任务所锻炼的关键技能是分析代码的实际作用,而不是人们从随便阅读或误导性的评论或演示中可能认为它所做的事情。它教授的另一项技能是详细遵循复杂的代码。当然,没有人应该编写令人困惑的代码,但不可否认的是,无论是否需要,在实践中都会出现令人困惑的代码,软件工程师必须熟练地了解代码实际在做什么。仅仅能够阅读和使用易于理解的代码是不够的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-27
      • 2010-11-11
      • 1970-01-01
      • 2011-12-08
      • 2011-03-11
      • 1970-01-01
      • 2020-07-07
      相关资源
      最近更新 更多