2012-04-25 91 views
6

我正在做一些家庭作业,并想知道是否有太多的嵌套while循环这样的事情。嵌套几个while循环有缺点吗?如果是的话,那么如何重构我下面的代码片段?嵌套许多while循环有问题吗?

下面是一次一行读取文件的代码,解析由某些定义的分隔符分隔的字段,并在打印到控制台之前移除前导空白。

// Read the file one line at a time 
while (fgets(lineStr, MAXLINELENGTH, fp) != NULL) 
{ 
    charPtr = strtok(lineStr, DELIMITERS); 

    // Loop until line is parsed 
    while (charPtr != NULL) 
    { 
     // Skip past leading whitespace 
     while (isspace(*charPtr)) 
      charPtr++; 

     puts(charPtr); 
     charPtr = strtok(NULL, DELIMITERS); 
    } 
} 
+6

不,嵌套循环没有问题。 – pmg 2012-04-25 22:49:22

+1

尽管您可能想要将其中的一些封装到反映他们正在做的事情的方法中 - 最后一个变成了'skipSpaces()'或其他类似的东西。 – 2012-04-25 22:51:16

+0

如果输入可以包含负值字符(*值大于127 *),您可能需要将参数转换为'isspace'以避免未定义的行为:'isspace((unsigned char)* charPtr)' – pmg 2012-04-25 22:51:20

回答

6

这实在是一个相当主观的话题。在我看来,三个嵌套while循环没有什么根本错误,但是你已经达到了可接受的极限。如果你想增加一两层嵌套,那么在我看来,你会越过期望读者理解的合理边界。人类的大脑只能在任何时候处理这​​么复杂的事情。

有些人会反驳我的观点,认为在一个函数中不应该有多于一层的嵌套,并且这些函数不应该包含超过10行左右的代码。相反的观点是,这样的政策会导致更加分散的,不相交的代码。我的经验法则是,如果你不能为一大块代码想出一个好的函数名称,那么也许这块代码并不是真正意义上的独立功能。

看看你可以打破这个功能的方式,有几个明显的选择。

  1. 将最外面的while的主体提取到单独的函数中。该提取的函数将处理一行。这将很容易命名和清晰阅读。
  2. 将跳过空格的while循环提取到单独的函数中。这将很容易命名,并会使您的代码更易于阅读。您将删除空白注释,因为提取的函数的名称会使其不必要。这可能是值得的。

如果您应用这些想法,然后你的代码看起来有点像这样:

char* skipWhitespace(char* str) 
{ 
    while (isspace(*str)) 
     str++; 
    return str; 
} 

void parseLine(char *lineStr) 
{ 
    charPtr = strtok(lineStr, DELIMITERS); 
    while (charPtr != NULL) 
    { 
     charPtr = skipWhitespace(charPtr); 
     puts(charPtr); 
     charPtr = strtok(NULL, DELIMITERS); 
    } 
} 
...... 
while (fgets(lineStr, MAXLINELENGTH, fp) != NULL) 
    parseLine(lineStr); 

注意的提取方法重构和命名,使评论有点多余的,我把他们赶走。另一个很好的经验法则是,如果你需要对代码进行过多评论,那么它可能还没有得到充分考虑。

最终,确实没有硬性规定,这归结为判断和个人偏好。在我看来,问题中的代码非常清晰易读,但我认为重构版本更清晰一些。

声明:我对代码的正确性或其他方面没有任何评论。我简单地忽略了这一点。

+1

我喜欢你的'没有名字,没有功能'的经验法则。显然只是一个指导方针,但它带回家一个好点 - 如果你不能描述该功能将做什么,你可能不需要它是一个功能! – corsiKa 2012-04-25 23:06:42

+0

感谢您重构的代码。将不得不问教授,如果他喜欢的代码是原样或更喜欢个人嵌套循环重构到他们自己的职能。我确实喜欢没有评论的想法,因为函数名称足够清楚地表达想法。 – Peter 2012-04-25 23:18:36

+0

你更喜欢哪一种?你应该至少有一个意见,并准备在你去找教授时以某种方式辩论。 – 2012-04-25 23:19:46

3

唯一真正的缺点是可读性,其中并没有真正的硬性规定,尽管超过3个巢通常会刺激你正在使用的任何其他人。正如另一张海报所说,有时它更好地通过将循环移动到另一个函数来打破嵌套,但您在这里的内容对我来说是完全可读的,而那是唯一真正的度量标准;纯粹的主观意见:)

0

如前所述,这是相对主观的。但是,嵌套循环的方式可能会对代码产生直接的性能影响。考虑缓存感知编程。也就是说,您希望以这样的方式安排您的代码,以便处理器可以在需要之前将下一个数据块预取(即预测)到缓存中。这将允许更多的缓存命中和更快的内存访问时间。

请注意,这对于您的示例并不特别重要,但是,如果您正在进行多次内存访问,则这可能会显着提高或降低性能。如果您在行主架构中以列方式遍历多维数组,则可能有很多缓存未命中(请注意,缓存未命中在实时方面的代价非常高)。

所以嵌套循环不一定是坏的,但它肯定会对性能有明显的影响,特别是在某些任意数目的循环之后。