標籤:
一.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的寫法比較好。因為程式更加簡潔。
switch_case,&&,||,條件操作符和逗號操作符,迴圈語句