2012-04-25 87 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

如前所述,這是相對主觀的。但是,嵌套循環的方式可能會對代碼產生直接的性能影響。考慮緩存感知編程。也就是說,您希望以這樣的方式安排您的代碼,以便處理器可以在需要之前將下一個數據塊預取(即預測)到緩存中。這將允許更多的緩存命中和更快的內存訪問時間。

請注意,這對於您的示例並不特別重要,但是,如果您正在進行多次內存訪問,則這可能會顯着提高或降低性能。如果您在行主架構中以列方式遍歷多維數組,則可能有很多緩存未命中(請注意,緩存未命中在實時方面的代價非常高)。

所以嵌套循環不一定是壞的,但它肯定會對性能有明顯的影響,特別是在某些任意數目的循環之後。