《GNU C编程教程》bug问题

3

我正在阅读"The GNU C Programming Tutorial",并且我认为我发现了一个非常微小而微妙的错误。这在章节中。在delete_multiples_of_prime(...)函数中,在for循环中:

delete_multiples_of_prime (int prime)
{
  int index, multiplier = 2;

  for (index = prime * multiplier; index < ARRAY_SIZE; index = prime * multiplier++)
    sieve[index] = DELETED;
}

我认为问题出现在 for 循环的增量部分。作者使用了后置递增运算符而不是前置递增运算符,因此我认为循环将以初始索引值执行两次。

我的理解正确吗?

注:我相当确定自己是对的,如果我在其他地方找到了这个答案,就不会发帖询问了。当然,即使我是对的,性能差异也可以忽略不计。


是的,你似乎是正确的。 - Fredrik
你是正确的。这不会影响函数的正确性,因为将一个元素标记为已删除两次并没有什么害处。 - Barmar
3
顺便说一句:这篇教程不太好。它最初是在1987年编写的,似乎没有更新以符合现代C语言标准(特别是声明没有返回类型的函数已不再被允许)。你真的应该找一些更近期的资料…… - user149341
@duskwuff 我知道这有点过时了(缺少返回类型并不是第一个迹象)。但是,我已经在使用C语言编程一段时间了,并且正在使用它来复习我的C语言知识以准备面试。我搜索了一段时间,发现这是我找到的最好的免费资源。你能否推荐另外一个类似的资源(适用于测试,且是免费或便宜的电子书/ PDF格式)? - dv1729
3
我会使用更简单的循环: for (int index = prime * 2; index < ARRAY_SIZE; index += prime)。不需要进行太多的乘法运算。 - Jonathan Leffler
1
请注意,Jonathan Leffler的方法(1)消除了错误(2),消除了不必要的变量,并且(3)更易于理解,因为它避免了对副作用的依赖,因此更容易正确实现。 - Peter
1个回答

3
您说得对,对于第一个索引,循环确实运行了两次。
然而,这并不是一个错误,因为赋值是幂等操作,所以对于给定索引的多个赋值将没有进一步的影响或副作用。即使第一个索引重复两次,函数也总是会按照相同的方式工作。
从性能上讲,差异应该可以忽略不计,因为每个函数调用只会有一个额外的赋值操作。(由于幂等性,编译器也可能被简单地优化掉)。
话虽如此,为了清晰起见,并且以防万一for循环体不再是幂等的(例如添加printf语句),我个人会使用前缀递增。
for (index = prime * multiplier; index < ARRAY_SIZE; index = prime * ++multiplier)

1
个人而言,我会避免在首次使用表达式(在这种情况下)时就产生副作用。正如你所说,这个错误在这种情况下是微不足道的,但类似的技巧(涉及具有多个效果和副作用的表达式)可能会引起非常难以跟踪的重大错误。而在团队环境中,造成问题的罪魁祸首通常并不是找到并纠正问题的人。 - Peter

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