if (x % 2 == 0) printf("x is even.\n"); else printf("x is odd.\n");
這裡的%是取模(Modulo)運算符,x%2
表示x
除以2所得的餘數(Remainder),C語言規定%運算符的兩個操作數必須是整型的。兩個正數相除取餘數很好理解,如果操作數中有負數,結果應該是正是負呢?C99規定,如果a
和b
是整型,b
不等於0,則表達式(a/b)*b+a%b
的值總是等於a
,再結合第 5 節 “表達式”講過的整數除法運算要Truncate Toward Zero,可以得到一個結論:%運算符的結果總是與被除數同號(想一想為什麼)。其它編程語言對取模運算的規定各不相同,也有規定結果和除數同號的,也有不做明確規定的。
取模運算在程序中是非常有用的,例如上面的例子判斷x
的奇偶性(Parity),看x
除以2的餘數是不是0,如果是0則打印x is even.
,如果不是0則打印x is odd.
,讀者應該能看出else
在這裡的作用了,如果在上面的例子中去掉else
,則不管x
是奇是偶,printf("x is odd.\n");
總是執行。為了讓這條語句更有用,可以把它封裝(Encapsulate)成一個函數:
void print_parity(int x) { if (x % 2 == 0) printf("x is even.\n"); else printf("x is odd.\n"); }
把語句封裝成函數的基本步驟是:把語句放到函數體中,把變數改成函數的參數。這樣,以後要檢查一個數的奇偶性只需調用這個函數而不必重複寫這條語句了,例如:
print_parity(17); print_parity(18);
if/else
語句的語法規則如下:
語句 → if (控製表達式) 語句 else 語句
右邊的“語句”既可以是一條語句,也可以是由{}括起來的語句塊。一條if
語句中包含一條子語句,一條if/else
語句中包含兩條子語句,子語句可以是任何語句或語句塊,當然也可以是另外一條if
或if/else
語句。根據組合規則,if
或if/else
可以嵌套使用。例如可以這樣:
if (x > 0) printf("x is positive.\n"); else if (x < 0) printf("x is negative.\n"); else printf("x is zero.\n");
也可以這樣:
if (x > 0) { printf("x is positive.\n"); } else { if (x < 0) printf("x is negative.\n"); else printf("x is zero.\n"); }
現在有一個問題,類似if (A) if (B) C; else D;
形式的語句怎麼理解呢?可以理解成
if (A) if (B) C; else D;
也可以理解成
if (A) if (B) C; else D;
在第 1 節 “繼續Hello World”講過,C代碼的縮進只是為了程序員看起來方便,實際上對編譯器不起任何作用,你的代碼不管寫成上面哪一種縮進格式,在編譯器看起來都是一樣的。那麼編譯器到底按哪種方式理解呢?也就是說,else
到底是和if (A)
配對還是和if (B)
配對?很多編程語言的語法都有這個問題,稱為Dangling-else問題。C語言規定,else
總是和它上面最近的一個if
配對,因此應該理解成else
和if (B)
配對,也就是按第二種方式理解。如果你寫成上面第一種縮進的格式就很危險了:你看到的是這樣,而編譯器理解的卻是那樣。如果你希望編譯器按第一種方式理解,應該明確加上{}:
if (A) { if (B) C; } else D;
順便提一下,浮點型的精度有限,不適合用==運算符做精確比較。以下代碼可以說明問題:
double i = 20.0; double j = i / 7.0; if (j * 7.0 == i) printf("Equal.\n"); else printf("Unequal.\n");
不同平台的浮點數實現有很多不同之處,在我的平台上運行這段程序結果為Unequal
,即使在你的平台上運行結果為Equal
,你再把i
改成其它值試試,總有些值會使得結果為Unequal
。等學習了第 4 節 “浮點數”你就知道為什麼浮點型不能做精確比較了。