• 文章
  • 條件語句 - 真假故事
作者:
2008 年 8 月 11 日 (最後更新:2008 年 8 月 14 日)

條件語句 - 真假故事

評分:3.2/5 (24 票)
*****
我又一次看到了一段類似於下面這個非常常見的錯誤的程式碼

1
2
3
4
5
6
if (chr == 'Y' || 'y') // this will always return true
  do_something; // and this will always be called
else if (chr == 'N' || 'n') // this makes same mistake as above
  do_something_else; // but, this will never be called because of above
else
  do_some_other_thing; // This will never be called 


在深入探討第一個 if 語句為何總是返回 true 之前,讓我們先來看看條件語句的一些工作細節。

什麼是條件語句? 條件語句是評估為 true(真)或 false(假)的語句。您所有的控制結構都依賴於條件語句。這包括...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ( conditional )
else if ( conditional )

while ( conditional )

do { ... }
  while ( conditional )

// even
for ( initialization; conditional; incremental)
// for loops can have an empty conditional which evaluates to true. But this only works for For loops.

// and there is the conditional operator
int a = conditional ? ... : ...;


由於條件語句評估為 truefalse,因此上面的內容也可以這樣編寫...

1
2
3
4
5
6
7
8
9
10
11
if (true)
else if (true)

while (true)

do { ... }
  while (true)

for ( ...; true; ...)

int a = true ? ... : ...;


當然,if (true) 會失去 if 語句的意義,但 while (true) 卻非常常用。

那麼我們如何定義真或假呢? 很多人會告訴你 false,而 true 是任何大於 的數。這並不完全準確。更精確地說,false,而 true 是任何 非零 值。這包括負數。(我已經透過 DevC++ 測試確認了這一點

False 也可以是 null,這與 zero 有明顯區別。有許多函式返回 null,因此這也可以用作條件語句。

那麼什麼可以算作條件語句? 任何評估為 truefalse 的東西。您所有的比較,例如 大於 '>',小於等於 '<=',以及 等於 '==',都會評估為 truefalse

1
2
3
4
5
6
7
8
9
10
11
12
int i = 5; // integer i is equal to five.

if (i == 5) // this evaluates to
if (true)

else if (i < 5) // this evaluates to
else if (false)

while (i >= 5) // this evaluates to
while (true)

// and so forth 


您所有的賦值也都會評估為 truefalse。這是因為賦值也返回一個值。a = 5; 將數字 5 儲存到變數 a 中。但它也返回 5 這個值。這就是為什麼 b = a = 5; 可以工作的原因。它首先將 5 儲存到 a 中,然後返回 5,這個 5 又被儲存到 b 中。

b = 5; 也返回 5,但由於我們沒有將其儲存到任何其他地方,所以它消失在時間和空間中,再也看不見了。這沒關係,因為總有一天有人會發明一個以這些四處漂浮的丟失值來獲取能量的超空間引擎。

1
2
3
4
5
6
7
8
// notice one '=' sign makes it an assignment, not a comparison
if (a = 5) // this evaluates into
if (5) // which since 5 is a non-zero, it evaluates into
if (true)

if (a = 0) // this evaluates to
if (0) // which as we know from above evaluates to
if (false)


最後,您還可以呼叫許多返回值的函式。任何不返回 void(或者根據 void 的定義,不返回任何東西)的函式都可以用作或包含在條件語句中。

邏輯運算子 有兩個邏輯運算子可用於連線條件語句。它們是 And '&&' 和 Or '||' 運算子。它們都接受兩個條件語句,一個在左邊,一個在右邊,並分別評估每個條件語句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if ( condition_1 || condition_2 ) // or
if ( condition_1 && condition_2 ) // and

int i = 5, j = 1;

if ( i == 3 || j == 1 ) // evaluates to
if ( false || true ) // evaluates to
if ( true )

if ( i == 5 && j == 3 ) // evaluates to
if ( true && false ) // evaluates to
if ( false )

// You can even use multiple concatenations.
int h = 3;

if ( i == 2 || ( j == 1 && h == 3 ) ) // evaluates to
if ( false || ( true && true ) ) // evaluates to
if ( false || true ) // evaluates to
if ( true )


這就回到了開頭的那段程式碼,以及它為何總是返回 true。那段程式碼是這樣的...

1
2
3
4
if (chr == 'Y' || 'y') // which if chr = anything other than 'Y' would evaluate to
if ( false || 'y' ) // and since 'y' is a non-zero this would evaluate to
if ( false || true ) // which will evaluate to
if ( true )


特別說明 您也可以將賦值和函式呼叫與邏輯運算子一起使用。但是,在這裡應該格外小心,因為這樣做可能會產生意想不到的結果。這是由於程式處理這些邏輯運算子的方式。

例如,Or 如果任一條件語句為 true,則返回 true。它會檢查第一個條件語句,如果返回 false,它會檢查第二個條件語句。但是,如果第一個條件語句返回 true,它就不需要檢查第二個條件語句了。它已經有足夠的資訊來返回 true。讓我們來看下面的程式碼示例...

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if (++i >= 5 || ++j >= 5) // OR
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


看到這段程式碼,人們可能會認為 i 和 j 都會達到 10。然而,一旦 i 達到 5,它就返回 true,因此第二個條件語句不再需要進行測試。結果如下所示。

1 1 false
2 2 false
3 3 false
4 4 false
5 4 true
6 4 true
7 4 true
8 4 true
9 4 true
10 4 true

然而,And 需要兩個條件語句都為 true。所以它會檢查第一個條件語句,如果它返回 true,它會檢查第二個條件語句。但是,如果第一個條件語句返回 false,就沒有理由檢查第二個條件語句了。它已經有足夠的資訊來返回 false。因此,下面的程式碼...

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if (++i >= 5 && ++j >= 5) // AND
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


...會產生以下輸出...

1 0 false
2 0 false
3 0 false
4 0 false
5 1 false
6 2 false
7 3 false
8 4 false
9 5 true
10 6 true

Not 運算子 當然,還有一個邏輯運算子需要考慮。就是 Not '!' 運算子,當放在條件語句前面時,它會簡單地反轉它。它將 true 變成 false,將 false 變成 true

1
2
3
4
5
6
7
if (!true) // evaluates to
if (false)

// and

if (!false) // evaluates to
if (true)


題外話:XOR 我最初將 Xor 列為邏輯運算子,但它不是。它是一個按位運算子。但是,在邏輯意義上模擬 Xor 功能是可能的。Xor 簡單來說就是‘Or And Not And’。但是,使用部分或全部賦值來實現這一點,其結果將更難預測。

1
2
3
4
5
6
7
8
9
10
11
12
   int i = 0, j = 0;
   while (true)
   {
      if ((++i >= 5 || ++j >= 5) && !(++i >= 5 && ++j >= 5))
         cout << i << " " << j << " true" << endl;

      else
         cout << i << " " << j << " false" << endl;

      if (i >= 10)
         break;
   }


...會產生如下輸出...

1 1 false
2 2 false
3 3 false
4 4 false
6 5 false
8 6 false
10 7 false