我正在做一些功课,想知道是否存在太多嵌套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);
}
}
答案 0 :(得分:7)
这确实是一个相当主观的话题。在我看来,三个嵌套的while循环没有任何根本性的错误,但是你达到了可接受的极限。如果您要添加一个或两个更多级别的嵌套,那么在我看来,您将跨越合理的边界,期望读者理解。人脑在任何一个时间点都只能处理如此复杂的事情。
有些人认为,与我的观点相反,函数中嵌套的级别不应超过一级,并且函数不应包含超过10行代码。反驳的论点是,这样的政策可能导致更加分散,不相交的代码。我的经验法则是,如果你不能为一大块代码想出一个好的函数名,那么也许那段代码实际上不是单独作为一个函数。
看看你可以打破这个功能的方法,有几个明显的选择。
while
的主体提取到一个单独的函数中。提取的函数将处理单行。这很容易命名和清楚阅读。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 :(得分:3)
唯一真正的缺点是可读性,对此没有任何硬性和快速的规则......虽然超过3个巢穴通常会刺激你正在使用的任何其他人。正如另一张海报所说,有时通过将循环移动到另一个功能来打破巢更好,但是你在这里拥有的东西对我来说是完全可读的 - 那是唯一真正的衡量指标;纯主观意见:))
答案 2 :(得分:0)
如前所述,这是相对主观的。但是,嵌套循环的方式会对代码产生直接的性能影响。考虑缓存感知编程。也就是说,您希望以这样的方式排列代码,即处理器可以在需要之前将下一个数据块预取(即预测)到高速缓冲存储器中。这将允许更多的缓存命中和更快的内存访问时间。
请注意,这对您的示例并不是特别重要,但是,如果要进行大量内存访问,则可能会显着提高或降低性能。如果您在行主体架构上以列方式遍历多维数组,则可能会出现许多缓存未命中(请注意,就实时而言,缓存未命中成本非常高。)
所以嵌套循环不一定是坏的,但它肯定会对性能产生明显的影响,特别是在一些任意数量的 n 循环之后。