一.switch-case
switch-case語句主要用在多分支條件的環境中,在這種環境中使用if語句會存在煩瑣且效率不高的弊端。
switch(expression)
{
case const expression1:
....
case const expression2;
...
default:
...
}
在執行過程中,expression的值會與每個case的值比較,實現switch語句的功能。關鍵字case和它所關聯的值被稱作case標號。每個case標號的值都必須是一個整形常量表達式,且不能存在兩個case標號相同的情形。除此之外,還有一個特殊的case標號-default標號。
如果expression的值與其中一個case標號相匹配,則程序將從該標號后面的第一個語句開始執行各個語句,直到switch結束或者遇到break語句為止,如果沒有發生與之匹配的case標號(並且也沒有default標號),則程序會從switch語句后面的一條語句繼續執行。
關於switch一般存在這樣的誤解:以為程序只會執行匹配的case標號相關的語句。實際上並非如此,該標號只是程序會執行的起始點,程序會從該點執行,並跨越case邊界繼續執行其他語句,直到switch結束或遇到break語句為止。
break語句的使用,是switch-case語句的核心。因為在大多數情況下,在下一個case標號前面必須加上一個break語句。
故意省略break是一種特別罕見的用法,因此在這種形式的代碼附近,請務必添加一些注釋,說明其運行邏輯。
在switch-case結構中,只能在最后一個case標號或default中定義內部變量。指定這種規則是為了避免出現代碼跳過變量定義和初始化的情況。
這個規則存在的原因:一般如果定義一個變量,此變量便從此定義開始有效,直到所在的語句塊結束。如果在兩個case中間定義一個變量,那么對於定義變量的case標號后面的其他標號都可以使用這個變量。但是如果switch從那些后續case標號開始執行呢?可能這個變量沒有定義就使用了,這是我們所不想看到的。為了實現在case中可以定義變量,可以引進語句塊思想實現。在該語句塊中定義變量,從而保證這個變量在使用前定義和初始化。而出了這個語句塊該變量就是非法了。所以,在case語句塊中,最好不要定義變量,所需的變量應在switch之前進行定義和初始化。如果必須定義變量,請謹慎而為,請采用語句塊方式實現內部變量的定義。
對於那些哪怕沒有語句在default標號下執行的環境中,定義default標號依然是有用的,定義default標號可明確地告訴讀者,這種情況已考慮到,只是沒有什么可以執行的。default標號不能單獨存在,它必須位於語句之前,如果switch以default結束,而default分支沒有什么任務需要執行,那么default標號后面必須添加 個空語句。
二.&&,||
&&和||是C++邏輯或和邏輯與操作符。在求值過程中,僅當a不能確定表達式的值時,才會求解b。在邏輯與表達式中,a的計算結果是true。如果a的計算結果是false,則無論b的值是什么,邏輯表達式的值都為false。當a的值為true時,只有b的值也為true時,邏輯與表達式的值才為true。在邏輯或中同樣,這就是短路求值。
&&和&,||和|的區別:&和|是位與和位或操作符。需要兩個整型操作數。&,在每個位的位置,如果兩個操作數對應的位都為1,則操作結果中該位為1,否則為0。|操作,在每個位的位置,如果兩個操作數對應的位只有一個為1,則操作結果中該位為1,否則為0;位操作符和邏輯操作符的每一個區別是||和&&操作符具有短路性質,如果表達式的值根據左操作數就可以決定,則它就不再對右操作數進行求值。與之相反,|和&操作符兩邊的操作數都需要進行求值。
在C++中,;標示一條語句的結束。如果不小心多寫了一個分號,可能不會造成什么不良的后果。這個分號可能會被當做一個不會產生任何效應的空語句;或者這個多余的分號被編譯器識別,編譯器會因為這個多余的分號產生一條警告語句,根據這個警告語句你可以很快找到並去掉它。但在if,for,while語句之后多加了一個分號,那么原來緊跟在if或者while子句之后的語句與條件判斷部分就沒有任何關系了。例如
int a = 1;
while(a == 1);
{
a--;
}
正常編譯,且循環
同樣少了分號也會帶來錯誤,例如
int arrIntMatrix[3] = {0,1,3}
void main()
{
int iIndex = 3;
if(iIndex<3)
return
arrIntMaxtrix[0] = 3;
}
分號標示C++語句結束,多了一個分號和少了一個分號都可能造成不良后果。應小心謹慎。
三.條件運算符和逗號運算符
條件運算符是C++語言唯一的"三目運算符"。其接受3個操作數,同樣條件的操作符會控制表達式的求值順序。用法如下:
expression1?expression2:expression3; (1)
(expression1)?(expression2):(expression3); (2)
條件運算符的優先級非常低,所以它的各操作數即使不加括號,一般也不會產生問題。但是為了表達的清楚性,還是傾向於在各個表達式兩端加上括號。首先計算expression1,如果值為真,那么整個表達式的值就是expression2的值,而expression3不會進行求值。否則,如果expression1的值為假,那么整個條件語句的值就是expression3的值,而expression2不會進行求值。
逗號操作符將兩個或多個表達式分隔開來,這些表達式自左向右逐個進行求值,而整個表達式的值是最后那個表達式的值。用法如下:
expression1,expression2,expression3,...,expressionn;
逗號操作符中的每個表達式會被求值,而整個表達式的值卻是最后一個表達式的值。因為這些表達式的求值順序已經固定,即采用從左到右的求值順序。常用在for語句的增量部分,即如果迭代變量不止一個的話,它就派上用場了, for(int i = 0,j=MAX;i<=j;++i,--j)
四.循環語句
不可在for循環全內修改循環變量,防止for循環失去控制,最終導致死循環等奇怪現象
建議for語句的循環控制變量的取值采用"半開半閉區間"寫法,因為這種寫法更加直觀。
x值屬於半開半閉區間"0<=x<N",起點到終點的間隔為N,循環次數為N x值屬於閉區間"0<=x<=N-1",起點到終點的間隔為N-1,循環次數為N
for(int x=0;x<N;x++) for(int x=0;x<=N-1;x++) //代碼1更加直觀
在C/C++循環語句中,for語句使用的頻率最高,while語句次之,do..while語句很少用。
在多重循環中,如果有可能,應將最長的循環放在最內層,最短的循環放在最外層,以減少CPU跨切循環層的次數。原因如下:最長循環放到內部可以提高I cache的效率,降低因為循環跳轉造成cache的miss以及流水線flush造成的延時,多次相同循環后也能提高跳轉預測的成功率,提高流水線效率。
示例1:for(row = 0;row<100;row++) 示例2:for(row = 0;row<100;row++)
for(col=0;col<5;col++) for(col=0;col<5;col++)
{ {
sum = sum+a[row][col]; sum = sum+a[row][col];
} }
示例1低效率,長循環在最外層,示例2高效率,長循環在最內層
如果循環體內存在邏輯判斷,並且循環次數很大,宜將邏輯判斷移到循環體的外面。
示例3:for(i = 0;i<100;i++) 示例4:if(condition)
{ {
if(condition) for(i = 0;i<100;i++)
DoSomething(); DoSomething();
else }else
DoOtherthing(); {
} for(i = 0;i<100;i++)
DoSomething();
}
示例3的程序比示例4多執行了N-1次邏輯判斷。並且由於前者總要進行邏輯判斷,打斷了循環"流水線"作業,使得編譯器不能對循環進行做優化處理,降低了效率。如果N非常大,最好采用示例4的寫法,可以提高效率。如果N非常小,兩者效率差別並不明顯,采用示例3的寫法比較好。因為程序更加簡潔。