C 嵌套许多while循环是否存在问题?

C 嵌套许多while循环是否存在问题?,c,while-loop,nested-loops,C,While Loop,Nested Loops,我正在做一些家庭作业,想知道是否有嵌套while循环太多这样的事情。嵌套几个while循环是否有缺点?如果是这样的话,如何重构我下面的代码片段 下面的代码一次读取一行文件,解析由一些定义的分隔符分隔的字段,并在打印到控制台之前删除前导空格 // Read the file one line at a time while (fgets(lineStr, MAXLINELENGTH, fp) != NULL) { charPtr = strtok(lineStr, DELIMITERS);

我正在做一些家庭作业,想知道是否有嵌套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);
    }
}

这真是一个相当主观的话题。在我看来,三个嵌套的while循环从根本上来说没有什么问题,但是您已经达到了可接受的极限。在我看来,如果你再增加一到两个嵌套层次,那么你就越过了期望读者理解的合理界限。人类的大脑在任何一个时间点都只能处理这么多的复杂性

有些人会反驳我的观点,认为函数中的嵌套不应超过一个级别,函数中的代码不应超过10行。相反的观点是,这样的策略可能会导致更零碎、不相交的代码。我的经验法则是,如果你不能为一段代码想出一个好的函数名,那么也许这段代码并不是真正意义上的独立函数

看看你可以用什么方法来分解这个函数,有几个明显的选择

  • 将最外层的
    主体提取到一个单独的函数中。提取的函数将处理一行。它很容易命名,也很容易阅读
  • 提取
    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);
    
    请注意,提取方法的重构和命名使得注释有点多余,我删除了它们。另一个很好的经验法则是,如果您需要对代码进行太多注释,那么可能它还没有得到很好的考虑

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


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

    唯一真正的缺点是可读性,对于这一点,没有任何硬性的规则。。。尽管超过3个巢穴通常会激怒你的同事。正如另一张海报所说,有时最好通过将循环移动到另一个函数来打破嵌套,但我完全可以理解这里的内容——这是唯一真正的度量标准;纯粹的主观意见:)

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

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


    因此,嵌套循环并不一定是坏的,但它肯定会对性能产生显著影响,特别是在一些任意数量的n循环之后。

    不,嵌套循环没有问题。尽管您可能希望将其中一些循环封装到反映它们所做操作的方法中,但最后一个循环将成为
    skipSpaces()
    ,如果输入可以包含负字符(值大于127),您可能希望将参数强制转换为
    isspace
    ,以避免未定义的行为:
    isspace((unsigned char)*charPtr)
    深嵌套可以指示您应该重构以将内容拆分为不同的函数。例如,您可以有一个解析一行的函数,然后是一个去除空白的函数,一个标记化的函数,等等。是的,这可能意味着多次通过缓冲区,但如果它不是性能关键用例,则更干净的模块化代码更好。我喜欢您的“无名称,无函数”经验法则。显然,这只是一个指南,但它带来了一个很好的观点-如果你不能描述函数将做什么,你可能不需要它成为一个函数!谢谢你的重构代码。将不得不询问教授,他是希望代码保持原样,还是希望将单个嵌套循环重构为它们自己的函数。我很喜欢没有注释的想法,因为函数名足够清晰,可以表达这个想法。你更喜欢哪一个?当你去教授那里时,你至少应该有一个观点,并准备好以这样或那样的方式进行辩论。我更喜欢函数。到目前为止,我们编写的所有代码都包含在测试代码调用的一个函数中,这将解释嵌套的whiles。我认为采用更复杂的编码方式应该不会有问题。将一些代码分解成专用函数将允许您重用这些函数。但是要注意,这些函数需要真正的良好格式,以便有效地重用。因此,
    skipWhitespace
    可能是重复使用的候选,但是
    parseLine
    必须只针对当前的问题(我猜)。