C語言探索之旅 | 第一部分第六課:條件表達式

1240

-- 簡書作者 謝恩銘 轉載請註明出處

第一部分第六課:條件表達式


上一課C語言探索之旅 | 第一部分第五課:運算那點事結束後,今天我們來學習《條件表達式》。

這一課和下一課《循環語句》很關鍵(你就說哪課不關鍵吧...),希望大家和我一起認真學習。

在之前的課程中,我們已經知道世界上有很多編程語言,有些相互之間很類似,其中不少都受了C語言的啓發。

事實上,C語言是很早之前被髮明的(1972年左右),比我都年長了好十幾歲,所以它也成了很多近代編程語言的參考模板。

我們說編程語言相似,是說他們都汲取了它們的前輩的編程基礎。

說到編程基礎,那就有很多了。其中,我們已經學過的有:變量,運算。這一課我們來學習條件表達式。

if…else條件表達式


簡單來說,條件表達式使我們可以測試變量。

打個比方,我們可以這樣說:

假如變量的值等於10,那就執行什麼什麼操作。

如果C語言裏面不能做“等於”的判斷,那該多可惜啊。我們還要做“小於”,“大於”,“大於等於”,“小於等於”,“不等於”的判斷。

不必擔心,C語言都爲您預備好了。

爲了學習if…else語句,我們準備按照下面的順序來進行:

  1. 預先需要了解的幾個符號

  2. if語句

  3. else語句

  4. else…if語句

  5. 多個條件

  6. 一些需要避免的錯誤

在我們學習寫if…else表達式前,須要先了解幾個基本符號,這些符號對於實現條件判斷是必不可少的。

幾個需要了解的符號


下表列出了C語言中需要用心記住的幾個符號

符號 含義
== 等於
> 大於
< 小於
>= 大於等於
<= 小於等於
!= 不等於

判斷“等於”需要兩個等號(==)!
一個很常見的錯誤是隻寫一個等號,在C語言中一個等號和兩個等號不是一個含義。
一個等號是表示賦值,兩個等號纔是判斷是否相等。

單一的if語句


邏輯是這樣的:

如果 變量的值是這樣
執行如下操作

所以單一的if語句是這樣寫的:

  1. 先寫一個if

  2. 接着寫一個括號(),在這個括號中寫條件

  3. 接着寫一個大括號{},在大括號中寫在()中條件爲真時所要執行的操作

格式如下:

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...");  // 兒語,聽不懂
}

流程是這樣的:

  1. 首先判斷第一個if語句中的括號裏的表達式,如果爲真,則執行第一個大括號裏的語句。

  2. 如果if的條件不爲真,則接着判斷else…if語句的括號裏的表達式,如果爲真,則執行對應的大括號裏面的語句。

  3. 如果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語句的理解:

假設你到了一個飯店,服務員給你看當日菜單:


=== 菜單 ===

  1. 北京烤鴨
  2. 鍋包肉
  3. 地三鮮
  4. 梅菜扣肉

您的選擇是?

然後根據你的選擇做出不同反應。應該怎麼寫呢?希望不要看答案,先自己寫代碼試試。

下面給出完整的示例程序:

#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。

事實上,三元表達式並不是那麼常用,因爲它會使代碼變得難讀,特別是當判斷條件多且複雜的時候。

總結


  1. 條件表達式是所有編程語言的基礎內容,使電腦能夠根據變量的值做出相應決定。

  2. 關鍵字“if”,“else...if”,“else”意味着“假如”,“又假如”,“否則”,我們可以寫多個“else...if”。

  3. 布爾變量是一種特殊的變量,它只有兩種狀態: 真(1)和假(0)(實際上,所有非零的整數值都被看作真),我們用整數類型int來儲存布爾變量的值,因爲C語言其實沒有定義布爾變量這種類型,而是用整數值來代表;像Java,C#等語言就定義了布爾類型。

  4. switch語句是if...else語句的一個可用替換,在有多個else...if的情況下,建議使用switch代替if...else語句,能使代碼更易閱讀。

  5. 三元表達式(xx ? xx : xx)是精簡的條件語句,但是我們要謹慎使用,因爲它會讓代碼不那麼易讀。

第一部分第七課預告


今天的課就到這裏,一起加油咯。

下一次我們學習 C語言探索之旅 | 第一部分第七課:循環語句

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章