今天的最后一个问题......我明天会回来......我有很多事要跟进......
我正在寻找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 ..
再次 - 你是否会认为这很糟糕 - 或者只是采取不同的方式...... 感谢...
答案 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=0
,i++
将等于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)。