為了應付程式可能遇到的各種狀況,C 提供了 if
條件判斷陳述,它的語法如下:
if (條件式)
陳述句一;
else
陳述句二;
這個語法的意思,白話來說,就是當條件式成立時(真),則執行陳述句一,要不然就執行陳述句二;如果條件式不成立時並不想作任何事,則 else
可以 省略。
在 if
後如果有兩個以上陳述句,稱之為複合陳述句(compound statement),此時你必須使用 {}
將複合陳述句包括起來,例如:
if (條件式) {
陳述句一;
陳述句二;
}
else {
陳述句三;
陳述句四;
}
if
或 else
中只有一個陳述句的時候,可以不寫 {}
,不過,現在鼓勵也是加上 {}
,這有助於可讀性,也有助於避免縮排上造成的程式碼閱讀誤解。
下面來寫個簡單的程式,判斷使用者的輸入是奇數還是偶數:
#include <stdio.h>
int main(void) {
int input = 0;
int remain = 0;
printf("輸入整數:");
scanf("%d", &input);
remain = input % 2;
if(remain == 1) {
printf("%d 為奇數\n", input);
}
else {
printf("%d 為偶數\n", input);
}
return 0;
}
執行結果:
輸入整數:10
10 為偶數
這個程式很簡單,使用餘數運算來計算除以2後的餘數,偶數的餘數會是 0,而奇數會是 1,由此判斷輸入為奇數還是偶數;事實上如果 C 瞭解非 0 值在判斷式中表示真,0 值表示假的意義的話,這個程式也可以這麼寫:
#include <stdio.h>
int main(void) {
int input = 0;
printf("輸入整數:");
scanf("%d", &input);
if(input % 2) {
printf("%d 為奇數\n", input);
}
else {
printf("%d 為偶數\n", input);
}
return 0;
}
在 if
中也可以再設定執行的條件,例如:
if (條件式一) {
陳述句一;
if(條件式二) {
陳述句二;
}
陳述句三;
}
這只個簡單的例子,其中陳述句二要執行,必須同時滿足條件式一與二才行;再來看個例子:
if (條件式一) {
陳述句一;
// 其他陳述句
}
else {
if(條件式二) {
陳述句二;
}
}
如果條件式一不滿足,就會執行 else
中的陳述,而你在這邊進行條件式二的測試,如果滿足就執行條件式二,由於單行陳述可以省略 {}
,而且 C 是個自由格式語言,可以適當地排列這個程式,這會比較好懂一些:
if (條件式一) {
陳述句一;
// 其他陳述句
}
else if(條件式二) {
陳述句二;
}
基於這個方式,可以如下設定多個條件,且易讀易懂:
if (條件式一) {
陳述一;
} else if(條件式二) {
陳述句二;
} else if(條件式三) {
陳述句三;
} else {
陳述句四;
}
陳述句四會在條件式一、二、三都不成立時執行;下面這個程式是個簡單的例子,處理學生的成績等級問題:
#include <stdio.h>
int main(void) {
int score = 0;
printf("輸入分數:");
scanf("%d", &score);
if(score >= 90) {
puts("得 A");
} else if(score >= 80 && score < 90) {
puts("得 B");
} else if(score >= 70 && score < 80) {
puts("得 C");
} else if(score >= 60 && score < 70) {
puts("得 D");
} else {
puts("得 E(不及格)");
}
return 0;
}
執行結果:
輸入分數:60
得 D
在這邊要注意的是,if
與 else
是就最近的一組來配對,例如下面這個程式依縮排來看,有什麼問題嗎?
if (條件式一)
if(條件式二)
陳述句一;
else
陳述句二;
很多人都會以為條件式一的 if
會與 else
配對,但事實上是條件式二的 if
與 else
配對,加上括號的話就可以一目瞭然了:
if (條件式一) {
if(條件式二) {
陳述句一;
} else {
陳述句二;
}
}
如果想避免這種錯誤,在程式中多使用括號是必要的,多寫一些總是比少寫一些來得保險一點。
如果想避免這種錯誤,在程式中多使用括號是必要的,多寫一些總是比少寫一些來得保險一點。
Apple 曾經提交一個 iOS 上的安全更新,原因是在某個函式中有兩個連續的縮排:
...
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
...
因為縮排在同一層,閱讀程式碼時開發者也就沒注意到,又沒有用 {}
定義區塊,結果就是 goto fail
無論如何都會被執行到的錯誤。