Skip to content

條件判斷 (Condition) 與迴圈 (Loop)

if 條件判斷

為了應付不同條件下能做出不同指令, C/C++ 提供了 if 條件句判斷。

條件句需要使用條件運算子,條件句有兩種結果,True (1) 和 False (0)。當 if 條件句符合時,會執行對應的陳述句,否則會無視陳述句,執行之後的程式碼。陳述句為一系列指令,可有 到多句,用 {} 包起來,只有 句時可省略,但為維護及可讀性,建議不要省略,

如果有兩種(含)以上的條件,可使用複合陳述句,當 if 條件不符合時,會執行 else if ,如果 else if 再不符合,會再執行下一個 else if ,直到遇到符合的條件句,就會執行對應的陳述句,如果執行到 else 則會無條件的執行對應的陳述句。在複合陳述句中,可以有 到多個 else if ,以及 else

if 條件判斷支持巢狀結構,意思為可以在 if 條件判斷裡面放 if 條件判斷。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 基本語法
if (條件_1)
{
    陳述_1;
}

// 複合陳述句
if (條件_1)
{
    陳述_1;
}
else if (條件_2)
{
    陳述_2;
}
... else if (條件_(n - 1)) { 陳述_(n - 1); }
else { 陳述n; }

// 巢狀 if
if (條件_1)
{
    if (條件_a)
    {
        陳述_a;
    }
}

// 範例,判斷 i 是否為奇數
scanf("%d", &i);
if (i % 2 == 0)
{
    printf("%d is odd\n", i);
}
else
{
    printf("%d is even\n", i);
}

if 條件判斷只能執行單次,如要重複執行,需使用迴圈,迴圈有兩種: whilefor

while 迴圈

while 迴圈用在終止條件未知的情況下。

執行順序為: 條件部 (符合)-> 陳敘 -> 條件部 (符合)-> 陳敘 ->...-> 條件部 (符合)-> 陳敘 -> 條件部 (不符合)-> 跳出。

當條件部的條件符合,才會執行陳敘。換句話說,只有當條件部的條件不符合,這個迴圈才會終止。

有個和 while 迴圈相似的迴圈叫做 do-while 迴圈,差別在於 do-while 會先執行陳敘,再判斷是否要離開迴圈。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// while 語法
while (條件部)
{
    陳敘;
}

// 範例,1 到 100 的總和
int i = 1, ans = 0;
while (i <= 100)
{
    ans += 1;
    i += 1;
}

// do-while 語法
do
{
    陳敘;
} while (條件部); // <- 這裡有分號,要注意

條件部可搭配遞增/遞減運算子,注意使用前綴和後綴。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

int main()
{
    int n = 5, m = 5;
    printf("prefix:");
    while (--n)
    {
        printf(" %d", n);
    }
    printf("\n");

    printf("postfix:");
    while (m--)
    {
        printf(" %d", m);
    }
    printf("\n");
}

/*
prefix: 4 3 2 1
postfix: 4 3 2 1 0
*/

for 迴圈

for 迴圈用在終止條件已知的情況下,會設立一個控制變數 (Control Variable) 來控制迴圈執行的次數。

for 迴圈分成初始部、條件部、更新部三部分

  • 初始部、條件部、更新部這三部分皆可省略。

  • 初始部:用來宣告和初始化控制變數( C99 前不能宣告),變數宣告只能是同種形態,如果有兩種(含)以上的形態要宣告,其中一種要宣告外部。

  • 條件部:判斷是否要繼續迴圈,同 while 迴圈的條件部。

  • 更新部:更新控制變數,更新部的值如果是要 +1-1 ,通常會使用遞增運算子。

  • 前綴後綴運算子,在更新部效果相同。在追求效率的程式競賽,會使用前綴遞增/遞減運算子,因為前綴遞增/遞減運算子,只會改變數的值,而後綴運算子,會先複製一個變數用於回傳,再改變數的值,效率會低於前綴運算子。

  • for 迴圈執行順序: 初始部 -> 條件部 (符合)-> 陳敘 -> 更新部 -> 條件部 (符合條件)-> 陳敘 -> 更新部 ->... 條件部 (符合)-> 陳敘 -> 更新部 -> 條件部 (不符合)-> 跳出。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// for 語法
for (初始部; 條件部; 更新部)
{
    陳敘;
}

// 範例,1 到 100 的總和
int ans = 0;
for (int i = 1; i <= 100; ++i)
{
    ans += 1;
}

whilefor 兩種寫法可以轉換,皆支持巢狀結構,可以和 if 搭配。

1
2
3
4
5
6
7
8
9
// 0~100 中的奇數和
int sum = 0;
for (int i = 0; i <= 100; i += 1)
{
    if (i % 2 != 0)
    {
        sum += i;
    }
}

breakcontinue

  • break :跳出迴圈。
  • continue :直接繼續下一次迴圈執行,跳過這次迴圈後續的程式碼。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>

int main()
{
    printf("break:");
    for (int i = 0; i < 5; ++i)
    {
        if (i == 2)
        {
            break;
        }
        printf(" %d", i);
    }
    printf("\n");

    printf("continue:");
    for (int i = 0; i < 5; ++i)
    {
        if (i == 2)
        {
            continue;
        }
        printf(" %d", i);
    }
    printf("\n");
}

/*
break: 0 1
continue: 0 1 3 4
*/

常見的輸入條件

比賽中會有一些輸入條件,常見有 EOF 版、 行版、X 尾版,以下一一介紹。

行版

這種題目格式如下:

1
第一行給一個數字 T,代表有 T 筆測資...

whilefor 迴圈可以這樣寫:

1
2
3
4
5
6
7
8
int T;
cin >> T;
while (T--)
{
}
for (int i = 0; i < T; ++i)
{
}

EOF 版

這種題目通常沒有明確的終止條件,或是直接告訴你「以 EOF 結尾」。

檔案結尾 (End of File, EOF),是指作業系統無法從資料來源讀取更多資料的情形,也就是一個程式讀資料讀到檔尾,程式遇到檔尾會回傳值,下列列出常用輸入函式(函式請參考 函式與遞迴章節 ):

如何模擬 EOF
  • 在 windows 的命令提示字元按 Crtl + Z
  • 類 Linux 系統按 Crtl + D
  • 也可以用 command line 編譯程式,重新導向輸入輸出

當讀到檔尾時, scanf 會回傳 -1 ,利用 scanf 的回傳值判斷是否獨到檔尾。

錯誤觀念
  • 錯誤:讀不到數字會變成 -1
  • 正確:讀不到 scanf() 會回傳 -1,也只有 C 的 scanf 會回傳 -1

cin 有兩種寫法,一種是利用函式 eof 判斷是否還有資料輸入。第二種是利用 cin 的回傳值,當讀到檔尾時, cin 會回傳空物件。空物件在 C++ 轉換成 bool 值會是 false ,可將結果轉換至 bool 值在判斷,在條件句裡面,所有回傳值都會變成 bool 值,不用特別轉換。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
int x;
// scanf
while (scanf("%d", &x) != -1)
{
}
// `EOF` 是 `C/C++` 語言的一個常數,為 `-1` ,可以用 `EOF` 代替 `-1`
// ,增加可讀性。
while (scanf("%d", &x) != EOF)
{
}

// cin
while (cin.eof())
{
    cin >> x;
}
while ((bool)cin >> x)
{
}
while (cin >> x)
{
}

另外附上 JAVApython 的 EOF 寫法:

1
2
Scanner sc = new Scanner(System.in);
while(sc.hasNext())
1
2
3
import sys

for s in sys.stdin:

X 尾版

1
... 最後輸入 X 結束。

X 可以是任意型態的任意值,例如數字的 -1 ,字元的 e

這種輸入有兩種寫法,一種是使用 break ,另一種是使用 C++ 的逗號運算子。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int x;
// 使用 break
while (scanf("%d", &x))
{
    if (x == -1)
    {
        break;
    }
}
while (cin >> x)
{
    if (x == -1)
    {
        break;
    }
}

// 使用 C++ 的逗號運算子
while (scanf("%d", &x), x != -1)
{
}
while (cin >> x, x != -1)
{
}