相對於 if 語句而言,switch 語句可以更方便地應用於多個分支的控制流程。C89 指明,一個 switch 語句最少可以支援 257 個 case 語句,而 C99 則要求至少支援 1023 個 case 語句。然而,在實際開發環境中,為了程式的可讀性與執行效率,應該盡量減少 switch 語句中的 case 語句。
除此之外,switch 語句與 if 語句不同的是,switch 語句只能夠測試是否相等,因此,case 語句後面只能是整型或字元型的常數或常數表示式;而在 if 語句中還能夠測試關係與邏輯表示式。
不要忘記在 case 語句的結尾新增 break 語句
在 switch 語句中,每個 case 語句的結尾不要忘記新增 break 語句,否則將導致多個分支重疊。當然,除非有意使多個分支重疊,這樣可以免去 break 語句。下面我們來看一個實際範例。
#include <stdio.h>
void print_week(unsigned int day);
void print_week(unsigned int day)
{
switch(day)
{
case 1:
printf("Mondayn");
break;
case 2:
printf("Tuesdayn");
break;
case 3:
printf("Wednesdayn");
break;
case 4:
printf("Thursdayn");
break;
case 5:
printf("Fridayn");
break;
case 6:
printf("Saturdayn");
break;
case 7:
printf("Sundayn");
break;
default:
printf("errorn");
break;
}
}
int main (void)
{
print_week(3);
return 0;
}
該程式中,在 print_week 函數中通過 switch 語句實現根據數位輸出星期名稱的功能。執行程式碼,程式將輸出“Wednesday”。
現在,如果將 case 1~case 4 的 break 語句去掉,如下程式碼所示,程式會輸出什麼結果呢?
#include <stdio.h>
void print_week(unsigned int day);
void print_week(unsigned int day)
{
switch(day)
{
case 1:
printf("Mondayn");
case 2:
printf("Tuesdayn");
case 3:
printf("Wednesdayn");
case 4:
printf("Thursdayn");
case 5:
printf("Fridayn");
break;
case 6:
printf("Saturdayn");
break;
case 7:
printf("Sundayn");
break;
default:
printf("errorn");
break;
}
}
int main (void)
{
print_week(3);
return 0;
}
執行結果為:
Wednesday
Thursday
Friday
不要忘記在 switch 語句的結尾新增 default 語句
在 switch 語句中,default 語句主要用於檢查預設情況,或者處理錯誤情況,如下面的範例程式碼所示:
default:
printf("errorn");
break;
如果在 switch 語句中去掉 default 語句,那麼 switch 語句將失去對預設情況與錯誤情況的處理能力。所以,奉勸大家不要偷懶,老老實實把每一種情況都用 case 語句來完成,而把真正對預設情況的處理交給 default 語句來完成。即使程式真的不需要 default 處理,也應該保留此語句:
default:
break;
這樣做並非畫蛇添足,可以避免令人誤以為你忘記了 default 處理。
不要為了使用 case 語句而刻意構造一個變數
在實際程式設計應用中,switch 中的 case 語句應該只用於處理簡單的、容易分類的資料。如果資料並不簡單,卻為了使用 case 語句而刻意構造一個變數,那麼這種變數很容易令我們得不償失。因此應該嚴格避免這種變數,並使用 if/else 結構來處理這類程式,如下面的範例程式碼所示:
char ch = c[0];
switch (ch)
{
case 'a':
f1();
break;
case 'b':
f2();
break;
case 'c':
f3();
break;
default:
break;
}
在上面的程式中,字元變數 ch 的值是取字元陣列 c[] 的第一個字元,與 case 語句中的常數值逐一進行比較。很顯然,這種方法存在一個嚴重的問題。
例如,如果字元陣列 c[] 中儲存的是“ab”字串,那麼 c[0] 會取第一個字元“a”與 case 語句進行匹配,因此會匹配到第一個 case 語句,並呼叫 f1() 函數。然而,如果字元陣列 c[] 中儲存的是其他以字元 a 開頭的字串(比如“abc”“abcd”“abcde”等),因為 c[0] 始終會取第一個字元的關係,因此它們同樣會匹配第一個 case 語句而呼叫 f1() 函數。其他的 case 語句同理。很顯然,這並不是我們想要的結果。
由此可見,當為了使用 case 語句而刻意構造一個變數時,真正的資料可能不會按照我們所希望的方式對映到 case 語句。因此,我們應該嚴格避免為了使用 case 語句而刻意構造一個變數,並使用 if/else 結構來處理這類程式,如下面的範例程式碼所示:
if(0 == strcmp("ab",c))
{
f1();
}
else if(0 == strcmp("bc",c))
{
f2();
}
else if(0 == strcmp("cd",c))
{
f3();
}
else
{
}
盡量將長的 switch 語句轉換為巢狀的 switch 語句
有時候,當一個 switch 語句中包括很多個 case 語句時,為了減少比較的次數,可以把這類長 switch 語句轉為巢狀 switch 語句,即把發生頻率高的 case 語句放在一個 switch 語句中,作為巢狀 switch 語句的最外層;把發生頻率相對低的 case 語句放在另一個 switch 語句中,放置於巢狀 switch 語句的內層。
例如,下面的程式碼把發生頻率相對較低的情況放置於預設的 case 語句內。
void print_week(unsigned int day)
{
switch(day)
{
case 1:
printf("Mondayn");
break;
case 2:
printf("Tuesdayn");
break;
case 3:
printf("Wednesdayn");
break;
case 4:
printf("Thursdayn");
break;
case 5:
printf("Fridayn");
break;
default:
switch(day)
{
case 6:
printf("Saturdayn");
break;
case 7:
printf("Sundayn");
break;
default:
printf("errorn");
break;
}
}
}
在上面的程式碼中,假設 case 6 與 case 7 不經常發生,因此將它們放置到巢狀 switch 語句的最內層。從表面看,雖然這樣損失了程式的一定可讀性,但當 case 語句很多,並且確實有些 case 語句發生的頻率比較低時,這種解決方案還是可取的。