使用!=与计数器控制的循环

时间:2009-06-18 18:30:21

标签: java c++

今天的最后一个问题......我明天会回来......我有很多事要跟进......

我正在寻找Reilly Java文本 - 谈论反控制循环模式..(无论什么语言都没关系。)

用于计数器控制循环(for,while等)和嵌套循环的作者...使用!=进行测试...现在我意识到!=用于某些具有事件控制循环的情况 - 如哨兵或EOF类型的循环 - 但对我来说 - 使用它与计数器控制循环是一个坏主意...非常容易出错..

示例:

x = 0;
while (x != 100) {
   y = 0;
  while (y != 100) {

   ...
   y++;
 }
  x++;
}

仅仅说...使用其他关系运算符会更好......

x = 0;
while (x < 100) {   //or even better some defined constant...
   y = 0;
  while (y < 100) {

   ...
   y++;
 }
  x++;
} 

我所看到的通常是文本中提供的方式..classes.etc ..

再次 - 你是否会认为这很糟糕 - 或者只是采取不同的方式...... 感谢...

10 个答案:

答案 0 :(得分:6)

我只会用

while (x != 100)

如果我希望循环在x 完全 100时终止。所以在绝大多数情况下我会使用

while (x < 100)

这是反控制循环的常见现象。

编辑:第二个想法,我总是在一个反控制循环中使用for-syntax,所以这个例子应该是

for(int i=0; i < 100; ++i)

答案 1 :(得分:6)

您希望循环条件与所需的后置条件完全相反。

i= 0;
while( i != 100 ) {
    i += 1;
}
assert i == 100;

您可以简单地看到循环后置条件与循环终止条件完全匹配。没有神秘感。

此外,您可以从初始条件和身体证明它将达到100,而不会“以某种方式”神奇地跳过一个值。

如果你有一个非常复杂的循环体,那么简单的并行结构是必不可少的。

如果使用Weakest Precondition techniques从后置条件中导出循环,则循环条件将是如上所示的简单匹配条件。

i < 100是一个坏主意,因为你的循环可能有一个不正确的主体,导致变量严重增加并仍然“出现”工作。

答案 2 :(得分:6)

在Java中使用<更为常见。 Modern C ++使用!=

!=更有可能捕获代码中的错误。在大多数情况下,这是一件好事。如果由于某种原因,计数器不仅已达到但超过了界限(通常在第一次迭代时),那么正文将以非法值执行。只要循环体不隐藏错误,那么你将得到一个例外。如果正文隐藏错误,循环将执行数十亿次,显然存在错误。

例如,去年Adobe Flash的实施中发现了一个有趣的漏洞。可以使用作为数组的指针初始化为null。通常不是问题 - 只要首次取消引用,该过程就会安全地崩溃。但是,使用了<的循环,允许从不执行主体,然后允许执行继续。之后,可以在攻击者指定的位置写入内存。由于null的值始终为0,因此攻击者确切地知道正在写入哪些内存位置。如果循环使用!=,则不会发生这种情况。

答案 3 :(得分:5)

正如其他答案所示,
while(i < 100)是安全的*
while(i != 100)是精确的**

顺便说一句,你可能想尝试while(i++ < 100)for(i = 0; i < 100; ++i)而不是你所展示的更简单的while循环 - 忘记在循环结束时增加计数器是一个真正的痛苦。请注意,如果i=0i++将等于0,然后下一次递增i,++i将递增i然后等于1,因此对于while(i++ < 100), postfix ++运算符是必要的。

另请注意,如果i在条件中进行测试时为0,那么它在循环体中将为1(对于while示例),因此如果i是一个索引一个数组或其他东西,而不仅仅是跟踪循环迭代,你最好坚持使用for循环(在每次迭代后增加i)。


*:这里的安全意味着不太可能进入无限循环。它也是不安全的,因为它可以隐藏潜在的错误,如果循环不是微不足道的

**:确切地说,如果它没有完全符合您的预期,它将会失败,您会注意到。其他一些答案也描述了如何在这种循环中更好地保​​护你免受错误。

答案 4 :(得分:4)

使用“!=”超过“&lt;”的主要优点这是失败的事情,它应该失败

例如,如果某个地方的某个错误导致x进入设置为110的循环,则x < 100将永远不会进入循环 - 这是您在调试时可能会错过的事实。 OTOH,如果你使用x!=100,它将永远不会退出循环 - 这是调试中不可缺少的。

答案 5 :(得分:3)

我不认为&lt;必然会为你提供比!更多的保护。如果你有i以你未曾预料到的方式递增的情况,你应该抛出异常,而不是用&lt;。

将它扫到地毯下。

例如,如果你真的担心你的while循环搞乱,你可以这样做:

x = 0;
while (x != 100) 
{
   assert x >= 0;
   assert x < 100;

   y = 0;
   while (y != 100) 
   {    
     assert y >= 0;
     assert y < 100;

     ...
     y++;
   }
   x++;
}

这样,当你的循环超出界限时,你的程序立刻就会死掉(早期崩溃,经常崩溃)并且你知道你的代码搞砸了。

答案 6 :(得分:2)

我怀疑这可能与C ++迭代器有关。

如果您使用整数或指针,<具有明确定义的含义。如果您在循环中使用C ++迭代器,则可能未定义<,或者可能难以计算。

例如,在运行列表时,C ++方式将是:

for(std::list<foo>::const_iterator i = bar.begin(); i != bar.end(); ++i)

并且真正唯一能看到我是否在bar.end()之前的方法是无限增加i并查看它是否等于bar.end()。

以一如既往的方式做小事情有很大的价值。

答案 7 :(得分:1)

我认为它们在语义上是相同的,唯一的区别在于!=数字大于100显然也会满足&lt;将阻止任何大于100的数字通过。

然而,在给定的情况下,两个运算符将产生相同的输出。现在,如果x和y变量以某种方式在该代码之外被操作,那么“&lt;”这将是一个更好的方法,以确保即使他们输入的值为90,也确保在100处有一个截止值,并且如果他们以4000的值输入则根本无法继续。显然,你正在做什么的意图当时会决定你选择哪个运算符,通常有几种方法可以实现相同的结果而不是总是一种“正确”的方式。

答案 8 :(得分:0)

是。它们在语义上是相同的。

使用“&lt;”的第二种语法运算符是在这种情况下通常使用的人,并且看起来更直观(因为变量的值在循环中递增)。

答案 9 :(得分:-1)

最好使用小于&lt;在循环。代码中的错误可能会导致计数器增加两次。这意味着循环将突然变为无限循环(或直到你打破MAXINT)。