从0开始还是从1开始循环?哪个更好,为什么?

3

我读过/写过的大多数for循环都是从0开始的,说实话,我读过的大部分代码都用于嵌入式系统,它们使用的是C/C++语言。在嵌入式系统中,有时候代码的可读性不如代码效率重要。因此,我不确定以下哪种情况更好:

版本1

for(i = 0; i < allowedNumberOfIteration; i++)
{
//something that may take from 1 iteration to allowedNumberOfIteration before it happens
  if(somethingHappened)
  {
     if(i + 1 > maxIteration)
     {
       maxIteration = i + 1;
     }
  }
}

版本 2

for(i = 1; i <= allowedNumberOfIteration; i++)
{
//something that may take from 1 iteration to allowedNumberOfIteration before it happens
  if(somethingHappened)
  {
     if(i > maxIteration)
     {
       maxIteration = i;
     }
  }
}

我认为第一版更好的原因:

1.大多数循环从0开始。因此,有经验的程序员可能认为从0开始更好。

我认为第二个版本更好的原因:

  1. 公平地说,如果函数中有一个从0开始的数组会很棒,因为数组的索引从零开始。但是在这段代码中没有使用任何数组。

  2. 除此之外,第二个版本看起来更简单,因为您不必考虑“+1”。

我不知道的事情

1)是否存在性能差异?

2)哪个版本更好?

3)在决定起始点时是否需要考虑其他方面?

4)我是不是过于担心了?


5
在我看来,从0开始更自然,因为标准中的大多数(也许所有)范围都表示为 [begin, end),而你的范围是 (begin, end] - NathanOliver
5
是的,你担心得太多了。一个好的编译器会生成最快的循环形式,并在幕后进行调整,无形中实现。 - Mark Ransom
2
我在这种情况下唯一担心的是,在整个代码库中保持起始索引的一致性(适用的情况下)。 - Pandatyr
1
只需按照自己和他人都能理解的方式编写代码。必要时进行优化。 - user2556165
1
在嵌入式系统中,可读性并不像代码效率那样重要。你非常错误。特别是在需要超过10年维护的嵌入式系统中,可读性至关重要。首先要专注于编写清晰易懂的代码。不要进行过早的优化(这并不意味着编写过于复杂的代码)。在分析后优化热点。如果有一个良好的架构,这将从两个角度得到最佳代码。 - too honest for this site
显示剩余21条评论
3个回答

16

1) 不

2) 也不

3) 在C和C++中,数组是以零为基础的。

4) 是的。


我希望你能以两种不同的方式回答。 :) 这让我和一开始一样。 :) 我很想知道你个人会怎么做。 - Ali

5
在C++中,所有形式的数组都是以零为基础的。也就是说,它们的索引从零开始,一直到数组大小减一。例如,一个包含五个元素的数组将具有索引0到4(包括)。
这就是为什么大多数C++循环从零开始的原因。
关于您特定的问题清单,对于第1个问题,可能会有性能差异。如果您从1开始循环,则如果将该值用作数组索引,则每个迭代器都需要减去1。或者,如果增加数组的大小,则使用更多内存。
对于第2个问题,这取决于您正在遍历什么。如果是在数组索引上进行迭代,则从零开始的循环显然更好。但是,您可能需要从任何值开始循环,这实际上取决于您正在做什么和您试图解决的问题。
对于第3个问题,您需要考虑的是您正在使用循环来做什么。
至于第4个问题,也许有点影响。 ;)

我认为我在我的问题中解释了一个具体的情况,所以我认为问题可以得到具体的回答。考虑到我针对这个具体案例所写的所有内容,我很乐意知道您会选择哪个方案。 - Ali
@Ali 针对问题中展示的代码,我不会选择“任何一个”。因为计算“maxIteration”并不需要使用循环。 - Some programmer dude
正如我所说,这是针对嵌入式系统的,因此我需要等待硬件响应。我通过设置allowedNumberOfIteration来设置等待的阈值。然而,在大多数情况下,硬件会更早地响应。因此,我想跟踪运行系统几个小时后所需的最大迭代次数,并检查芯片变化是否影响了这个数字。如果我的问题没有表述清楚,我很抱歉。 - Ali

0

这个参数来自著名计算机科学家Dijkstra(Dijkstra算法的发明者)的一份小型三页笔记。在其中,他阐述了我们可能从零开始索引的原因,并且故事始于尝试迭代自然数序列(指数轴上的0、1、2、3等序列)。

有4种可能的方式来索引2、3、...、12。

a.) 2 <= i < 13

b.) 1 < i <= 12

c.) 2 <= i <= 12

d.) 1 < i < 13

他提到a.)和b.)的优点是两个边界之差等于序列中元素的数量。他还提到,如果两个序列相邻,则一个序列的上限等于另一个序列的下限。他说这并不能帮助决定使用a.)还是b.),所以他将重新开始思考。

他立即从列表中删除b.)和d.),因为如果我们从零开始一个自然序列,它们将具有超出自然数(-1)的边界,这是“丑陋”的。他补充说,我们更喜欢使用<=作为下限——留下a.)和c.)。
对于一个空集,他指出,在b.)和c.)中,其上限将为-1,这也是“丑陋”的。
所有这些观察结果都导致了用a.)来表示自然数序列的惯例,事实上,这就是大多数人编写遍历数组的for循环的方式:for(int i = 0; i < size; ++i)。我们包括下限(i <= 0),并排除上限(i < size)。
如果您要使用类似for(int i = 0; i <= iterations - 1; ++i)来执行i次迭代,您可以看到在空集的情况下他所指的“丑陋”。对于零次迭代,iterations - 1将为-1

因此,按照惯例,我们使用 a.),由于数组索引从零开始,我们在 for 循环中使用 i = 0 开始一个巨大的数字。然后,我们推理出简约性 - 如果没有其他原因要以不同的方式执行不同的操作,最好以完全相同的方式执行它们。

现在,如果我们使用 a.) 来进行基于 1 的索引而不是基于 0 的索引,则会得到 for(int i = 1; i < size + 1; ++i)。这个 + 1 看起来有点“丑陋”,所以我们更喜欢用 i = 0 开始我们的范围。

总之,你应该使用 for(int i = 0; i < iterations; ++i) 的循环语句进行 iterations 次迭代。像 for(int i = 1; i <= iterations; ++i) 这样的语句可以说是相当易懂且可行,但是否有任何好理由添加不同的循环方法来迭代 iterations 次呢?只需使用与索引数组相同的模式即可。换句话说,使用 0 <= i < size。更糟糕的是,基于 1 <= i <= iterations 的循环并没有所有 Dijkstra 提出的支持使用 0 <= i < iterations 作为一种惯例的理由。
你不用太担心。实际上,Dijkstra 本人曾经和几乎所有认真编程的人一样想过同样的问题。调整你的风格就像一个热爱自己手艺的工匠站在的基础上。追求简洁和按照其他人(包括你自己——数组的循环!)编写代码的方式都是值得追求的健康的事情。
由于这个约定,当我看到for(i = 1时,我注意到与约定的偏离。然后我会更加谨慎地处理那段代码,认为for内部的逻辑可能依赖于从1而不是0开始。虽然这只是微小的差别,但没有理由在如此广泛使用的约定中添加这种可能性。如果你碰巧有一个很大的for体,这个抱怨就变得不那么微小了。

要理解为什么从1开始没有意义,考虑将论点自然地推向结论——“但对我来说很有意义的”这一论点:你可以从任何一个数字开始循环变量i!如果我们从常规中解放出来,为什么不循环 for(int i = 5; i <= iterations + 4; ++i)?或者 for(int i = -5; i > -iterations - 5; --i)?只需要像大多数程序员在大多数情况下所做的那样,并在有充分理由时才采取与众不同的方式——不同之处表明了你的代码中的for的主体包含了一些不寻常的内容。使用标准方法,我们知道for要么是从0开始索引/排序/执行算术运算的序列,要么是连续执行某种逻辑iterations次。

请注意这种惯例是多么普遍。在 C++ 中,每个标准容器都在 [start, end) 之间迭代,这对应于上面的 a.)。在那里,他们这样做是为了使结束条件可以是 iter != end,但我们已经按照一种方式进行逻辑操作,并且这种方式没有立即的缺点,自然地流入了“为什么要以两种不同的方式进行操作,当我们已经在这种情况下以这种方式进行操作?”的论点中。在他的小论文中,Dijkstra 还提到了一种称为 Mesa 的语言,它可以使用特定的语法执行 a.)、b.)、c.) 或 d.)。他声称,在那里,a.) 在实践中获胜,而其他方法则与错误的原因相关联。然后,他哀叹 FORTRAN 索引从 1 开始,而 PASCAL 则通过惯例采用了 c.)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接