8

我正在做一些功课,想知道是否有太多嵌套的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);
    }
}
4

3 回答 3

8

这确实是一个相当主观的话题。在我看来,三个嵌套的 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);

请注意,提取方法的重构和命名使注释有点多余,我删除了它们。另一个好的经验法则是,如果您需要过多地注释代码,那么它可能还没有被很好地考虑。

归根结底,确实没有硬性规定,这取决于判断和个人喜好。在我看来,问题中的代码非常清晰易读,但在我看来,重构后的版本更加清晰一些。

免责声明:我不对代码的正确性或其他方面发表评论。我只是忽略了这方面。

于 2012-04-25T22:54:10.300 回答
3

唯一真正的缺点是可读性,对此并没有任何硬性规定……尽管超过 3 个嵌套通常会激怒与您一起工作的任何其他人。正如另一位海报所说,有时最好通过将循环移动到另一个函数来打破嵌套,但你在这里所拥有的对我来说是完全可读的——这是唯一真正的指标;纯粹的主观意见:)

于 2012-04-25T22:54:12.580 回答
0

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

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

所以嵌套循环不一定是坏事,但它肯定会对性能产生明显的影响,尤其是在一些任意数量的n循环之后。

于 2012-04-25T23:01:24.137 回答