Language agnostic 循环终止条件

Language agnostic 循环终止条件,language-agnostic,for-loop,conditional,correctness,Language Agnostic,For Loop,Conditional,Correctness,这些循环是算法形式正确性证明的第一个基本示例。它们具有不同但等效的终止条件: 1 for ( int i = 0; i != N; ++i ) 2 for ( int i = 0; i < N; ++i ) 1表示(int i=0;i!=N;++i) 2表示(int i=0;i=N的弱保证,但您可能会尝试假设i==N 如果出于任何原因,增量++i被更改为i+=2,或者i在循环内被修改,或者N为负值,则程序可能会失败: 第一个可能陷入无限循环。它在出现错误的循环中很早就失败了

这些循环是算法形式正确性证明的第一个基本示例。它们具有不同但等效的终止条件:

1   for ( int i = 0; i != N; ++i )

2   for ( int i = 0; i < N; ++i )
1表示(int i=0;i!=N;++i)
2表示(int i=0;i
后条件中的差异变得明显:

1   for ( int i = 0; i != N; ++i )

2   for ( int i = 0; i < N; ++i )
  • 第一种方法给出了循环终止后
    i==N
    的有力保证

  • 第二种方法只给出了循环终止后
    i>=N
    的弱保证,但您可能会尝试假设
    i==N

如果出于任何原因,增量
++i
被更改为
i+=2
,或者
i
在循环内被修改,或者
N
为负值,则程序可能会失败:

  • 第一个可能陷入无限循环。它在出现错误的循环中很早就失败了。调试很容易

  • 第二个循环将终止,在稍后的某个时间,由于您错误地假设
    i==N
    ,程序可能会失败。它可能会在远离导致错误的循环的地方失败,从而难以追溯。或者它可以默默地继续做一些意想不到的事情,甚至更糟


您喜欢哪种终止条件,为什么?还有其他考虑吗?为什么很多程序员知道这一点,拒绝应用它?< /P> < P>在C++中,使用<代码>!出于通用性考虑,首选代码>测试。C++中的迭代器有各种概念,例如,每个都用新的能力扩展了先前的概念。对于
,我们不应该孤立地看待计数器-如果出于任何原因,有人改变了计数器递增的方式,他们会改变终止条件和结果逻辑(如果i==N需要)


我更喜欢第二个条件,因为它更标准,不会导致无休止的循环。

如果您信任您的代码,您可以这样做

如果你想让你的代码易读易懂(从而对那些你认为是笨蛋的人的改变更宽容),我会使用如下的东西

for ( int i = 0 ; i >= 0 && i < N ; ++i) 
for(int i=0;i>=0&&i
我总是使用#2,这样您就可以确定循环将终止。。。依赖于它等于N之后就是依赖于一个副作用。。。使用变量N本身不是更好吗


[编辑]对不起…我是说#2

一般来说我更喜欢

for ( int i = 0; i < N; ++i )
for(int i=0;i
对生产中出现错误的程序的惩罚似乎要轻得多,您不会让线程永远卡在for循环中,这种情况可能非常危险,也很难诊断


另外,一般来说,我喜欢避免使用这种循环,而使用更具可读性的foreach样式的循环。

我认为大多数程序员使用第二种循环,因为它有助于了解循环内部的情况。我可以看到它,并且“知道”我将从0开始,并且肯定小于N

第一种变体没有这种质量。我可以看看它,我所知道的是,我将从0开始,它永远不会等于N。这没有多大帮助

无论您如何终止循环,在循环之外使用循环控制变量总是非常谨慎的。在您的示例中,您(正确地)在循环内声明了i,因此它不在循环外的范围内,并且它的值的问题是没有意义的

当然,第二个变体还有一个优点,就是我看到的所有C引用都使用它:-)

我更喜欢使用#2,只是因为我尽量不将I的含义扩展到for循环之外。如果我跟踪一个这样的变量,我会创建一个额外的测试。有人可能会说这是多余或低效的,但它提醒读者我的意图:在这一点上,我必须等于N


@timyates-我同意人们不应该依赖副作用,我倾向于使用第二种形式,因为这样我可以更确定循环会终止。也就是说,通过改变循环中的I,很难引入非终止错误

当然,它还有一个稍微懒惰的优点,即可以少键入一个字符;)


我还认为,在具有合理范围规则的语言中,正如我在循环构造中声明的那样,它不应该在循环之外可用。这将减少对循环结束时i等于N的依赖…

我想你已经很好地说明了两者之间的区别。不过,我有以下评论:

    <>这不是“语言不可知论”,我可以看到你的例子是C++,但是在那里 是不允许修改循环变量的语言 循环和其他不保证索引值在 循环(有些循环同时进行)

  • 您已经声明了
    i
    中为
    建立索引,这样我就不会在循环后对
    I
    的值下注。 这些示例有点误导,因为它们含蓄地假设
    for
    是 一个确定的循环。实际上,这只是一种更方便的写作方式:

    // version 1
    { int i = 0;
      while (i != N) {
        ...
        ++i;
      }
    }
    
    请注意,在块之后,
    i
    是如何未定义的


如果程序员知道以上所有内容,不会对
i
的值进行一般假设,并且明智地选择
i在c中使用上述任何一项,那么如果在循环外使用i,则会导致编译器错误

,有时我更喜欢这样:

for (int i = 0; (i <= (n-1)); i++) { ... }

对于(inti=0;(i对于一般编程工作,我更喜欢

for ( int i = 0; i < N; ++i )
因为它不太容易出错,尤其是当代码被重构时。我曾看到这种代码意外地变成了一个无限循环

那个论点说“你会被诱惑去假设i==N”,我不相信这是真的。我从来没有做过这样的假设,也没有看过其他的进展
for ( int i = 0; i != N; ++i )