-- 簡書作者 謝恩銘 轉載請註明出處
第一部分第六課:條件表達式
上一課C語言探索之旅 | 第一部分第五課:運算那點事結束後,今天我們來學習《條件表達式》。
這一課和下一課《循環語句》很關鍵(你就說哪課不關鍵吧...),希望大家和我一起認真學習。
在之前的課程中,我們已經知道世界上有很多編程語言,有些相互之間很類似,其中不少都受了C語言的啓發。
事實上,C語言是很早之前被髮明的(1972年左右),比我都年長了好十幾歲,所以它也成了很多近代編程語言的參考模板。
我們說編程語言相似,是說他們都汲取了它們的前輩的編程基礎。
說到編程基礎,那就有很多了。其中,我們已經學過的有:變量,運算。這一課我們來學習條件表達式。
if…else條件表達式
簡單來說,條件表達式使我們可以測試變量。
打個比方,我們可以這樣說:
假如變量的值等於10,那就執行什麼什麼操作。
如果C語言裏面不能做“等於”的判斷,那該多可惜啊。我們還要做“小於”,“大於”,“大於等於”,“小於等於”,“不等於”的判斷。
不必擔心,C語言都爲您預備好了。
爲了學習if…else語句,我們準備按照下面的順序來進行:
-
預先需要了解的幾個符號
-
if語句
-
else語句
-
else…if語句
-
多個條件
-
一些需要避免的錯誤
在我們學習寫if…else表達式前,須要先了解幾個基本符號,這些符號對於實現條件判斷是必不可少的。
幾個需要了解的符號
下表列出了C語言中需要用心記住的幾個符號
符號 | 含義 |
---|---|
== | 等於 |
> | 大於 |
< | 小於 |
>= | 大於等於 |
<= | 小於等於 |
!= | 不等於 |
判斷“等於”需要兩個等號(==)!
一個很常見的錯誤是隻寫一個等號,在C語言中一個等號和兩個等號不是一個含義。
一個等號是表示賦值,兩個等號纔是判斷是否相等。
單一的if語句
邏輯是這樣的:
如果 變量的值是這樣
則 執行如下操作
所以單一的if語句是這樣寫的:
-
先寫一個if
-
接着寫一個括號(),在這個括號中寫條件
-
接着寫一個大括號{},在大括號中寫在()中條件爲真時所要執行的操作
格式如下:
if (/* 條件 */)
{
// 如果條件爲真,所要執行的操作
}
我們把上面註釋的地方換成實際的代碼,來寫一個程序測試一下:
#include <stdio.h>
int main(int argc, char *argv[])
{
int age = 20;
if (age >= 18)
{
printf ("你成年了!\n");
}
return 0;
}
解釋:
int age = 20;
首先定義一個int型的變量,名字是age(英語: 年齡),值爲20。
if語句的括號()中的條件是 age >=18,意思是“假如age的值大於或等於18”。
if語句的大括號{}中的語句是
printf ("你成年了!\n");
就是說當age的值大於或等於18時,顯示“你成年了!”這句話。
因爲程序中變量age的值是20, 大於18,所以條件爲真,所以程序運行起來後顯示:
你成年了!
如果我們把變量age的值改爲12,再次運行程序,什麼也沒顯示,因爲12小於18,所以 age >= 18 這個條件不爲真,不執行大括號裏的printf語句
嘮叨一下代碼的格式
假如上面的代碼我們寫成這樣:
if(age>=18){printf("你成年了!");}
程序也是可以正確運行的,但是非常不推薦這樣的代碼格式!
如果我們的程序沒有空行,沒有空格,不縮進,都寫在一行裏,那將會使代碼非常難以閱讀。
所以從一開始學習編程就請養成良好的編碼習慣,不然以後寫一些大型程序,別人根本不知道怎麼閱讀你的代碼,你也會迷失在自己的代碼裏。
推薦看林銳老師的《高質量C++/C 編程指南》一書,裏面有提到編碼規範,可以去網上下載PDF。
當然每個程序員的代碼風格都不一樣,但是我們推薦大家遵從本系列課程中的代碼格式,因爲是比較通用的編碼格式。
else語句
現在你知道怎麼寫單一的if語句了,那當條件爲假時,我們要電腦也執行對應的操作怎麼辦呢?對了,此時就輪到else關鍵字出場了。
但是else語句一定要跟if語句配合才能使用,獨立的else語句是不可用的!
至於關鍵字,是電腦語言裏事先定義的,有特別意義的標識符,有時又叫保留字,是有特別意義的變量。
C語言有不少關鍵字,比如int,float,char,double,if,else,等,暫時我們不多涉及,可以去了解一下。
之前關於變量的那一課,變量的命名,其實忘記講了一點: 變量的名字不要跟關鍵字重名
所以一個完整的 if...else 語句的格式是:
if (/* 條件 */)
{
// 條件爲真的時候,所要執行的操作
}
else // 如果上面()裏的條件爲假
{
// 條件爲假的時候,所要執行的操作
}
再用之前測試年齡的例子,來寫一下實際的程序
if (age >= 18) // 如果age變量的值大於或等於18
{
printf ("你成年了!");
}
else // 如果age變量的值小於18
{
printf ("你還未成年,可以任性!");
}
如果age的值大於或等於18,則打印“你成年了!”;如果age的值小於18,則打印“你還未成年,可以任性!”。
else...if語句
上面我們學習瞭如何用單一的if語句,以及if...else語句
其實除了“假如...”(if語句)和“否則...”(else語句),還有else...if(“又假如”)語句,用於在if語句的條件不爲真時對其他的情況的判斷,else…if語句放在if語句和else語句之間。
邏輯是這樣的:
如果變量值爲A,則執行if對應操作
如果變量值不爲A,而爲B,則執行else...if對應操作
如果變量值不爲A也不爲B,則執行else對應操作
我們也用一個實例來看一下if,else…if和else合在一起用的情況:
if (age >= 18) // 如果age(英語:年齡)變量的值大於或等於18
{
printf ("你成年了 !");
}
else if ( age > 4 ) // 如果age小於18但是大於4
{
printf ("還好你不是太年幼");
}
else // 如果age小於或等於4
{
printf ("mama, guagua, blablabla..."); // 兒語,聽不懂
}
流程是這樣的:
-
首先判斷第一個if語句中的括號裏的表達式,如果爲真,則執行第一個大括號裏的語句。
-
如果if的條件不爲真,則接着判斷else…if語句的括號裏的表達式,如果爲真,則執行對應的大括號裏面的語句。
-
如果if和else…if裏的表達式都爲假,則無需再判斷,直接執行else語句的大括號裏的命令。
在完整的條件語句塊中,else…if和else語句不是必須的,但是必須要有一個if語句。
我們可以寫任意多的else…if語句,但是if語句和else語句則都是最多有一個。
else後面是沒有括號()的,但是if和else…if後面都有括號,也就是都包含判斷條件,應該不難理解吧,很合乎邏輯。
多個條件
我們也可以在條件語句的括號()中測試多個條件表達式。
例如,你想要測試這個人的年齡是不是介於18歲和25歲之間,就需要兩個條件表達式來判斷了。
爲了達成我們的目的,我們需要用到新的符號:
符號 | 含義 | ||
---|---|---|---|
&& | 邏輯與 | ||
邏輯或 | |||
! | 邏輯非 |
本來其實上表中的幾個應該也叫做:與,或,非。但爲什麼叫“邏輯與”,“邏輯或”和“邏輯非”呢?
那是因爲之後我們還會學到 &,| 等符號,稱爲“按位或”和“按位與”。暫時不用知道什麼意思,之後會學到。
邏輯與
如果我們要做上面提到過的年齡的判斷,則需要用邏輯與:
if (age > 18 && age < 25)
兩個 & 號連在一起表示邏輯與,就是說當兩邊的表達式都爲真時,括號中的整個表達式才爲真,所以這裏只有當age大於18並且小於25的情況下,括號裏的表達式才爲真。
邏輯或
爲了做邏輯或判斷,我們則要用到兩個 | 符號。邏輯或只要其兩邊的兩個表達式有一個爲真,整個表達式就爲真。我承認這個符號在鍵盤上不容易輸入。
假設我們現在要寫一個程序,目的是判斷一個人是不是夠資格開設銀行賬戶。
衆所周知,要開一個銀行賬戶,申請人不能太年幼(我們假定需要大於20歲)或者有很多錢(有錢任性嘛,即使是10歲小孩,也得讓他開戶)。
所以我們的程序是像以下這樣:
if (age > 20 || money > 150000)
{
printf("歡迎來到**銀行 !");
}
else
{
printf("我還不夠資格,悲催啊 !");
}
所以這個測試只有當申請人年齡大於20歲或者擁有超過15萬現金時,才讓其開戶。
邏輯非
我們最後要看的符號是感嘆號,表示“取反”,加在表達式之前。
如果表達式爲真,那麼加上感嘆號則爲假;如果表達式爲假,那麼加上感嘆號則爲真。就是跟你“唱反調”。
例如:
if (!(age < 18))
上面的表達式表示“假如已經成年”(不小於18歲)。
當然,邏輯與和邏輯或可以連用,甚至多個一起用,例如:
if ((age > 18 && age < 25) || age < 4)
一些容易犯的錯誤
== 號
不要忘了之前講過的 == (兩個等號)是用於判斷是否相等。例如:
if (age == 18)
{
printf ("你剛成年 !");
}
上例中如果錯把 == (兩個等號)寫成了 = (單個等號),那後果很嚴重,表達式就變成 age = 18了。
單個等號是賦值,所以age變爲18,整個表達式的值變爲18,就起不到判斷的作用了。
一種避免這樣錯誤的寫法是“18 == age”,這樣如果我們漏寫了一個等號,變成“18 = age”,那編譯器會報錯,因爲常量(18)不能做左值。
關於左值和右值,可以去搜索網上的資料,簡單來說“位於賦值運算符兩側的兩個值,左邊的就叫左值,右邊的就叫右值”。
多餘的分號(;)
還有一個經常會犯的錯誤是:在if的括號或者else...if的括號後面多加了一個分號,如下:
if (age == 18); // 注意這個分號,本來不應該出現的
{
printf ("你剛好成年");
}
上面的代碼實際上相當於
if (age == 18)
{
;
}
{
printf ("你剛好成年");
}
看到沒有,分號就相當於if語句的大括號裏的執行語句,而 ; 是空語句,什麼也不執行。
我們原先想讓其在age等於18時執行的printf語句卻成了一個必定會被執行的語句,不論age的值是不是等於18(大括號是可以把多個語句集合起來的分隔區域,可以拿掉大括號再來理解)。
可能有點暈,好好多看幾遍代碼。
布爾值,條件語句的核心
我們現在更加深入地來看if...else條件語句。事實上,條件表達式(這裏指括號裏的表達式)在其內部是做了布爾值的判斷。
布爾類型英語叫boolean,是隻能取“真”或者“假”的一種變量類型。
事實上,在其他的一些編程語言,如Java,C++,C#中,本身定義了boolean類型,只能有兩個值,true(真)和false(假)。
但是C語言沒有定義boolean類型,怎麼辦呢?
不用擔心,C語言把零作爲假,非零的一切值都算爲真
我們可以做幾個小測試來加深理解:
if (1)
{
printf("真!");
}
else
{
printf("假!");
}
以上代碼執行結果是顯示:
真!
可以把1換成非零的任意int型整數:5,9,13,-2,448等等,結果都會顯示:
真!
if (0)
{
printf("真!");
}
else
{
printf("假!");
}
以上代碼執行結果是顯示:
假!
所以C語言中只有0是假,其他非零的值都被看作真。這就是C語言的“布爾類型”,因爲C語言沒有定義真正的布爾值類型。
必要的一些解釋
事實上,每當你在條件表達式裏做判斷時,如果表達式是真的,則整個表達式的值是1;如果是假的,則整個表達式的值爲0。
例如:
if (age >= 18)
假如age的值爲25,是大於等於18的,那麼 age >= 18這個表達式的值爲真,電腦其實會把它替換爲1。
假如age的值爲15,是小於18的,那麼 age >= 18這個表達式的值爲假,電腦其實會把它替換爲0。
用變量來測試一下:
#include <stdio.h>
int main(int argc, char *argv[]) {
int age = 25;
int adult = 0;
adult = age >= 18;
printf("adult的值是 : %d\n", adult);
return 0;
}
運行,顯示:
adult的值是 : 1
如果age爲15,則顯示:
adult的值是 : 0
這裏的adult其實已經是一個C語言中的“布爾值”了。
switch語句
我們剛學的if...else類型的條件語句是最常用的。
但是C語言還給出了if...else語句的一個替代語句:switch語句。
因爲,有時候,當我們的條件判斷很多時,就會感覺冗餘。例如下面的代碼:
if (age == 2)
{
printf("寶寶,你好 !");
}
else if (age == 6)
{
printf("小朋友,你好 !");
}
else if (age == 12)
{
printf("少年,你好 !");
}
else if (age == 16)
{
printf("青少年,你好 !");
}
else if (age == 18)
{
printf("成年人,你好 !");
}
else if (age == 67)
{
printf("爺爺,你好 !");
}
else
{
printf("對你的年齡我還沒有對應的問候方式");
}
之前我們也說過,程序員(IT工作者)是很懶惰的,他們不喜歡做重複,單調的工作。
因此,爲了避免重複寫一些代碼,他們發明了新的switch語句。
以下展示了用switch語句改寫的上面那個if...else語句的例子:
switch (age)
{
case 2:
printf("寶寶,你好 !");
break;
case 6:
printf("小朋友,你好 !");
break;
case 12:
printf("少年,你好 !");
break;
case 16:
printf("青少年,你好 !");
break;
case 18:
printf("成年人,你好 !");
break;
case 67:
printf("爺爺,你好 !");
break;
default:
printf("對你的年齡我還沒有對應的問候方式 ");
break;
}
switch語句雖然沒有if...else語句那麼常用,但是對於判斷情況很多的條件語句,用switch是不是可以少寫不少代碼呢,而且程序也一目瞭然,比較清晰。
switch語句的格式
-
首先,寫switch這個關鍵字,接着寫一個括號,括號裏面是要判斷的變量
-
case加上變量可能的取值,再加一個冒號,再加上對應取值時的操作,再加上一個break;
要注意:case後面的值只能是整型或字符型的常量或常量表達式
-
default負責處理除了各個case以外的情況
-
多個case就相當於if...else語句裏的if和else...if
-
default相當於if...else語句裏的else
想想看,switch語句是不是很像我們去飯店用餐:
服務員拿了一個酒水單給你,上面有好多飲料,就像好多個case後面的取值,你點一種飲料,服務生就去給你拿對應的飲料,這個操作就像case的冒號後面的語句。
假如你什麼都不要,說:還是給我來杯水吧,那服務生就只能給你拿一杯水了,就相當於default。
每個 case 語句的結尾絕對不要忘了加 break,否則將導致多個分支重疊(除非有意使多個分支重疊)。
假如上例中我們少寫了一個break;,看看會變成怎樣:
int age = 2;
switch (age)
{
case 2:
printf("寶寶,你好 !\n");
// 這裏我們沒有寫 break;
case 6:
printf("小朋友,你好 !\n");
break;
case 12:
printf("少年,你好 !");
break;
case 16:
printf("青少年,你好 !");
break;
case 18:
printf("成年人,你好 !");
break;
case 67:
printf("爺爺,你好 !");
break;
default:
printf("對你的年齡我還沒有對應的問候方式 ");
break;
}
上面的代碼,當age的值爲2的時候,顯示的內容是:
寶寶,你好 !
小朋友,你好 !
很奇怪吧,這是因爲沒有break,程序就不跳出switch的大括號,而繼續執行,“穿透”了case 6,雖然age的值是2,不等於6,但是也執行了case 6對應的語句
printf("小朋友,你好 !\n");
因爲case 6的執行語句後面加了break,所以程序執行完
printf("小朋友,你好 !\n");
就跳出了switch語句。當然有時候也有故意不加break,使得多個情況做同一個操作的,例如:
switch (age)
{
case 2:
case 6:
case 12:
case 16:
printf("未成年人,你好 !");
break;
case 18:
printf("成年人,你好 !");
break;
case 67:
printf("爺爺,你好 !");
break;
default:
printf("對你的年齡我還沒有對應的問候方式 ");
break;
}
上面的代碼,當age的值爲2或6或12或16時,都會執行
printf("未成年人,你好 !");
是不是也很妙呢?
break關鍵字的作用不僅於此(用於跳出switch語句),在下一課《循環語句》中我們會更深入學習break的作用。
還有要注意的是:最後必需使用 default 分支。
雖然default不加其實也不會報錯,但即使程序真的不需要 default 處理,也應該保留語句,這樣做並非畫蛇添足,可以避免讓人誤以爲你忘了 default 處理。
要把 default 子句用於檢查真正的默認情況。
稍微有點暈?沒關係,讓我們用一個更完整的例子來加深對switch語句的理解:
假設你到了一個飯店,服務員給你看當日菜單:
【
=== 菜單 ===
- 北京烤鴨
- 鍋包肉
- 地三鮮
- 梅菜扣肉
您的選擇是?
】
然後根據你的選擇做出不同反應。應該怎麼寫呢?希望不要看答案,先自己寫代碼試試。
下面給出完整的示例程序:
#include <stdio.h>
int main(int argc, char *argv[])
{
int choiceMenu;
printf("=== 菜單 ===\n\n");
printf("1. 北京烤鴨\n");
printf("2. 鍋包肉\n");
printf("3. 地三鮮n");
printf("4. 梅菜扣肉\n");
printf("\n您的選擇是 ? ");
scanf("%d", &choiceMenu);
printf("\n");
switch (choiceMenu)
{
case 1:
printf("您選了北京烤鴨。這是本店的招牌菜 !");
break;
case 2:
printf("您選了鍋包肉。您是東北人吧?知道宋佳嗎?她最喜歡吃鍋包肉了!");
break;
case 3:
printf("您選了地三鮮。實惠好吃,就是油有點多.");
break;
case 4:
printf("您選了梅菜扣肉。嗯,那個味道很棒!");
break;
default:
printf("您沒有選擇餐單上的數字,難道您要餓肚子嗎 ?");
break;
}
printf("\n");
return 0;
}
以上代碼可以根據用戶輸入的不同數字做出相應的應答。
三元表達式:精簡的條件語句
除了if...else語句和switch語句,還有第三種條件語句,比switch更少用。
我們稱其爲 三元表達式。
更確切地說,其實它就是一個if...else的變體,只不過我們把它寫在一行裏了。
因爲實例總比長篇的解釋來得更清晰易懂,所以我們用兩個例子來說明。
這兩個例子的功能相同,只不過第一個使用if...else語句,第二個使用三元表達式。
假設我們有一個布爾類型的變量adult,當“成年”時它的值爲真(1),當“未成年”時它的值爲假(0)。
我們還有一個int型變量age,要根據adult的值來改變age變量的值,下面先給出if...else的實現:
if (adult)
age = 18;
else
age = 17;
注意:上例中我把if和else對應的大括號給去掉了,在只有一句執行語句的時候,去掉大括號是可以的,兩句或以上就須要加上大括號了。
不過其實按照良好的代碼習慣,應該無論如何都加上大括號。
上例用三元表達式實現則是這樣:
age = (adult) ? 18 : 17;
三元表達式使我們可以只用一行代碼來根據條件改變變量的值。
問號表示首先判斷adult是不是真值,如果是真,則取問號後面的18,將18賦給age;如果爲假,取冒號後面的17,將17賦給age。
這裏的問號就有點像if的條件判斷,冒號就像else。
事實上,三元表達式並不是那麼常用,因爲它會使代碼變得難讀,特別是當判斷條件多且複雜的時候。
總結
-
條件表達式是所有編程語言的基礎內容,使電腦能夠根據變量的值做出相應決定。
-
關鍵字“if”,“else...if”,“else”意味着“假如”,“又假如”,“否則”,我們可以寫多個“else...if”。
-
布爾變量是一種特殊的變量,它只有兩種狀態: 真(1)和假(0)(實際上,所有非零的整數值都被看作真),我們用整數類型int來儲存布爾變量的值,因爲C語言其實沒有定義布爾變量這種類型,而是用整數值來代表;像Java,C#等語言就定義了布爾類型。
-
switch語句是if...else語句的一個可用替換,在有多個else...if的情況下,建議使用switch代替if...else語句,能使代碼更易閱讀。
-
三元表達式(xx ? xx : xx)是精簡的條件語句,但是我們要謹慎使用,因爲它會讓代碼不那麼易讀。
第一部分第七課預告
今天的課就到這裏,一起加油咯。
下一次我們學習 C語言探索之旅 | 第一部分第七課:循環語句