目錄
1 復雜表達式的計算過程
2 if-else語句
2.1 基本結構及示例
2.2??if-else if 多分支
2.3?嵌套 if-else
2.4?懸空的 else
2.5 注意事項
2.5.1 if 后面不要加分號
2.5.2 省略 else
2.5.3 省略 {}
2.5.4 注意點
3 while 循環
3.1 一般形式
3.2 流程特點
3.3 注意事項
3.3.1 while 后面不能加分號
3.3.2?使用花括號括起循環體
4 do-while 循環
4.1 一般形式
4.2?注意事項
5 for 循環
5.1 一般形式
5.2?執行過程
5.3 省略寫法
5.3.1?省略初始化表達式
5.3.2?省略循環條件表達式
5.3.3?省略更新表達式
5.3.4?省略所有表達式
5.4 注意事項
5.4.1?for后面不能加分號
5.4.2?循環條件的正確性
6 三種循環的選擇
6.1 for循環
6.2 while循環
6.3?do-while循環
7?continue?語句
7.1 語法及示例
7.2 注意事項
7.2.1 對于while循環
7.2.2 對于do-while循環
8?break?語句
8.1 語法及示例
8.2 注意事項
8.2.1?只會跳出當前所在的最內層結構
8.2.2 適用范圍
9 小節判斷題
10 OJ 練習
10.1?課時4作業1
10.2?課時4作業2
10.3?課時4作業3
1 復雜表達式的計算過程
程序員控制程序執行邏輯運算需要選擇和循環結構,首先我們來講選擇語句,在介紹選擇語句前,我們首先練習一下關系表達式與邏輯表達式。在第 3 章內容中,我們了解到算術運算符的優先級高于關系運算符、關系運算符的優先級高于邏輯與和邏輯或運算符、相同優先級的運算符從左至右進行結合等 ,簡單記就是:?! > 算術運算符 > 關系運算符 > && > || > 賦值運算符,那么表達式 5>3&&8<4-!0 的最終值是多少?計算過程是怎樣的?
大部分人容易想成以下錯誤的計算過程:
- 首先,分析表達式 5 > 3 && 8 < 4 - !0 。
- 先計算 !0 ,! 是邏輯非運算符,0 表示假,!0 就表示真,即值為 1 。
- 然后計算 4 -!0 ,即 4 - 1 ,結果為 3 。
- 接著計算 5 > 3 ,這是成立的,值為真,即 1 。
- 再計算 8 < 3 ,這是不成立的,值為假,即 0 。
- 最后計算 1 && 0 ,&& 是邏輯與運算符,只有當兩個操作數都為真時結果才為真,所以整個表達式的值為假,即 0 。
然而,正確的計算過程是:先計算 5 > 3 ,因為 && 的短路性質,具體步驟如下圖所示:
2 if-else語句
在你打開衣柜拿出最上面的一件衣服時,你會判斷這件衣服是不是你想穿的。如果是,那么你就會穿上;如果不是,那么你就會去找其他衣服。在計算機中,我們用“如果”判斷語句來實現這樣的效果:“如果”判斷條件(表達式)為真,就執行某個語句,反之不執行這個語句。當然,也可以“如果”判斷條件(表達式)為真,就執行某個語句,反之用“否則”分支執行另一個語句,具體流程如下圖 1 和圖 2 所示。
在 C 語言中,if-else 語句是一種基本的控制流語句,用于根據條件表達式的真假來執行不同的代碼塊。這種結構允許程序進行條件判斷,并根據判斷結果執行相應的操作。
2.1 基本結構及示例
if-else 語句的基本結構如下:
if (condition) { // 如果condition為真(true),則執行這里的代碼
} else { // 如果condition為假(false),則執行這里的代碼
}
- condition:是一個表達式,其結果必須是整型(在C語言中,非零值被視為真,零被視為假)。
- if 后的花括號 {} 內包含了當 condition 為真時要執行的語句。
- else 后的花括號 {} 內包含了當 condition 為假時要執行的語句。
示例1:
假設我們要編寫一個程序,根據用戶輸入的年齡來判斷其是否成年:
#include <stdio.h>int main() {int age;printf("請輸入你的年齡: ");fflush(stdout); //解決Clion中printf和scanf順序問題scanf("%d", &age);if (age >= 18) {printf("你已成年。\n");} else {printf("你還未成年。\n");}return 0;
}
在上面這個例子中,程序首先提示用戶輸入年齡,然后通過一個 if-else 語句來判斷年齡是否大于等于18歲。根據判斷結果,程序會輸出相應的信息。
輸出結果如下圖所示:
示例2:
判斷輸入值是否大于 0 ,當輸入值大于 0 時,打印 “i 是大于 0”,當輸入值小于等于 0 時,打印 “i 不是大于 0”,具體代碼如下例所示:
#include <stdio.h>int main() {int i;// 這里使用while循環主要是為了多次運行程序,一次一次啟動浪費時間while(scanf("%d",&i))if(i>0){//不要在括號后加分號printf("i is bigger than 0\n");}else{printf("i is not bigger than 0\n");}}return 0;
}
2.2??if-else if 多分支
“if 語句”和“else 語句”也可以多個同時使用(多分支語句),如下圖 3 所示。
else if 是 else 語句后緊跟著另一個 if 語句的簡寫,它允許你在一個 if-else 結構中測試多個表達式。如果 if 語句的條件為假,則程序會檢查 else if 的條件;如果 else if 的條件也為假,則繼續檢查下一個 else if(如果有的話);如果所有的 if 和 else if 條件都為假,并且存在一個 else 分支,則執行 else 分支中的代碼。
如下面這個例子,根據用戶輸入的分數,程序會輸出不同的評級:
#include <stdio.h> int main() { int score; printf("請輸入分數(0-100): "); scanf("%d", &score); if (score >= 90) { printf("優秀\n"); } else if (score >= 80) { printf("良好\n"); } else if (score >= 60) { printf("及格\n"); } else { printf("不及格\n"); } return 0;
}
在使用 if-else if 結構創建多分支時,無論有多少個 if 語句或 else if 語句,程序都只會執行這些條件語句中的一個。這是因為程序會按照順序檢查每個條件,一旦找到第一個為真的條件,就會執行與之對應的代碼塊,并跳過剩余的所有 else if 和 else 分支。
如果所有的 if 和 else if 條件都不滿足(即為假),并且存在 else 分支,則程序會執行 else 分支中的代碼。如果連 else 分支也沒有,那么程序將不會執行任何 if-else if-else 結構中的代碼,而是繼續執行該結構之后的代碼。
下面是一個簡單的示例,說明了這個過程:
#include <stdio.h> int main() { int number = 5; if (number == 1) { printf("Number is 1\n"); } else if (number == 2) { printf("Number is 2\n"); } else if (number == 5) { printf("Number is 5\n"); // 這個條件為真,因此會執行這個分支 } else if (number == 10) { printf("Number is 10\n"); // 這個條件為假,因此不會執行 } else { printf("Number is not 1, 2, 5, or 10\n"); // 也不會執行到這個分支 } return 0;
}
2.3?嵌套 if-else
else if 是處理多條件判斷的首選方式,但在某些情況下,可能需要嵌套 if 語句,即在一個 if 或 else 代碼塊內部使用另一個 if 語句。
?在下面這個例子中,我們首先檢查年齡,然后根據年齡的結果,我們進一步檢查身高。
#include <stdio.h> int main() { int age, height; printf("請輸入年齡: "); scanf("%d", &age); printf("請輸入身高(厘米): "); scanf("%d", &height); if (age >= 18) { if (height >= 170) { printf("您已經成年且身高達到或超過170厘米。\n"); } else { printf("您已經成年但身高不足170厘米。\n"); } } else { printf("您還未成年。\n"); } return 0;
}
2.4?懸空的 else
在 C 語言中,當使用嵌套的 if 語句時,必須明確每個 else 子句與哪個 if 語句相關聯,以避免所謂的“懸空的 else ”問題。這個問題通常發生在有多個 if 語句連續出現,并且至少有一個 if 語句后面跟著一個 else 語句時。
編譯器會根據大括號 {} 的嵌套來解析 else 子句與哪個 if 語句相關聯,但如果沒有明確使用大括號來限定每個 if 語句的作用域,那么 else 子句就會與最近的、尚未與 else 子句關聯的 if 語句相匹配。
示例:沒有使用大括號的懸空else問題
#include <stdio.h> int main() { int a = 1, b = 2; if (a > b) if (a == 1) printf("a is 1\n"); else // 這個else與哪個if相關聯? printf("a is not greater than b\n"); return 0;
}
在這個例子中,else 子句實際上與內層的 if (a == 1) 相關聯,而不是與外層的 if (a > b) 相關聯。這是因為編譯器將 else 子句與最近的、尚未匹配的if語句關聯起來。所以這個例子不會輸出打印任何語句!
修正:使用大括號明確作用域
為了避免這個問題,應該使用大括號 {} 來明確每個 if 語句的作用域,從而確保 else 子句與正確的 if?語句相關聯。
#include <stdio.h> int main() { int a = 1, b = 2; if (a > b) { if (a == 1) { printf("a is 1\n"); } } else { printf("a is not greater than b\n"); } return 0;
}
在這個修正后的例子中,外層的 if-else 結構被大括號明確限定,因此 else 子句現在與 if (a > b) 相關聯。
2.5 注意事項
2.5.1 if 后面不要加分號
在 C 語言中,“如果”(即 if 語句)后面直接加分號(;)通常是不合邏輯的,并且會導致編譯錯誤或者邏輯上的錯誤,具體取決于你的意圖和代碼上下文。
當你看到 if 后面緊跟一個分號時,這通常意味著 if 語句的條件部分之后沒有跟隨任何要執行的語句,或者開發者可能誤將某個語句放在了if語句的外部。這種用法往往是無效的或者是一個錯誤。
錯誤用法示例:
if (x > 0); // 這里有一個分號,但沒有跟隨任何語句
printf("x is positive\n"); // 這行代碼將無條件執行,因為它不在if語句塊內
在上面的例子中,printf 語句不會根據 x > 0 的條件來決定是否執行。因為 if 語句后有一個分號,它實際上是一個空的 if 語句,而 printf 語句總是在 if 語句之后無條件執行。
正確用法示例:
if (x > 0) { printf("x is positive\n"); // 只有當x > 0時,這行代碼才會執行
}
在這個例子中,if 語句正確地包含了要執行的代碼塊(由大括號 {} 包圍),并且該代碼塊內的語句僅當x > 0時才會執行。
2.5.2 省略 else
if-else 結構中的 else 部分是可以省略的。當你只關心某個條件為真時的情況,而不關心條件為假時的情況,或者條件為假時不需要執行任何操作時,就可以省略 else 部分。
省略 else 的 if 語句的基本形式如下:
if (condition) { // 當condition為真時執行的代碼
}
// else部分被省略了
這里是一個簡單的示例,它只在變量?x?大于?0?時打印一條消息:
#include <stdio.h> int main() { int x = 5; if (x > 0) { printf("x is positive\n"); } // 沒有else部分,所以x不大于0時不會執行任何操作 return 0;
}
2.5.3 省略 {}
在 C 語言中,當 if 或 else 語句塊內只有一條語句時,可以省略大括號 {}。這是為了簡化代碼和提高可讀性(盡管在某些情況下,省略大括號可能會降低可讀性,特別是當代碼變得復雜或需要修改時)。
if (x > 0) printf("x is positive\n");
else printf("x is not positive\n");
在這個例子中,if 和 else 語句塊內都只有一條語句,因此大括號被省略了。編譯器能夠正確地理解每個條件對應的執行語句。
即使只有一條語句,也建議使用大括號 {} 來明確語句塊的范圍,這有助于避免未來的錯誤。
2.5.4 注意點
選擇分支(if...else):
確保條件表達式的邏輯清晰準確,避免出現歧義或錯誤的判斷。
- 例如,不要寫成類似 if (a = 5) 這樣的錯誤形式,應該是 if (a == 5) 。
注意代碼的縮進和格式,以使結構清晰易讀。
多分支(if...else if...else):
按照條件的可能性和優先級合理安排分支的順序,將最可能滿足的條件放在前面。
- 例如,如果一個數值在大多數情況下處于某個特定范圍內,就應該先檢查這個范圍。
確保每個分支的條件是互斥的,避免出現重復判斷或遺漏的情況。
例如,下面是一個錯誤的多分支示例:
int num = 10;
if (num > 5) {printf("大于 5\n");
} else if (num > 8) { // 錯誤,因為如果 num 大于 8 必然大于 5,這與前面的分支邏輯沖突printf("大于 8\n");
} else {printf("小于等于 5\n");
}
而正確的應該是:
int num = 10;
if (num > 8) {printf("大于 8\n");
} else if (num > 5) {printf("大于 5 小于等于 8\n");
} else {printf("小于等于 5\n");
}
嵌套 if...else:
避免過度嵌套,以免代碼變得復雜難以理解。如果嵌套層次過多,可能需要考慮重構代碼。
同樣要注意條件的準確性和邏輯的清晰性。
- 例如,在內層的 if...else 中,要明確其與外層條件的關系。
對于復雜的嵌套結構,可以添加適當的注釋來解釋代碼的意圖。
3 while 循環
while 循環是 C 語言中的一種基本控制流語句,它實現了 “當型” 循環結構。
這種循環結構的特點是:在執行循環體內的語句之前,首先會評估一個條件表達式的值。如果條件表達式的值為非0(即真),則執行循環體內的語句;執行完畢后,再次評估條件表達式的值,如果仍為真,則重復執行循環體內的語句,如此往復,直到條件表達式的值為0(即假)時,循環結束,程序繼續執行while循環之后的代碼。
3.1 一般形式
while (表達式) { // 循環體(包含零條或多條語句)
}
- 表達式:這是每次循環開始前被評估的條件表達式。如果其值為真(非零),則執行循環體。
- 循環體:包含了一組將被重復執行的語句。這些語句在條件為真時執行。
3.2 流程特點
先判斷后執行:while循環首先檢查條件表達式的值。如果條件為真,則執行循環體;如果為假,則跳過循環體,繼續執行while循環之后的語句。
條件更新:為了避免死循環(即程序無限期地重復執行循環體),通常需要在循環體內部包含一些更新條件表達式的操作,以確保在某個時刻條件表達式的值會變為假,從而結束循環。
- 程序首先檢查 while 循環的條件表達式。
- 如果條件為真(即,條件表達式的結果是非零值),則執行循環體內的語句。
- 完成循環體內的所有語句后,程序再次回到步驟1,重新檢查條件表達式。
- 如果條件仍然為真,則再次執行循環體。這個過程會一直重復,直到條件變為假為止。
- 一旦條件變為假,程序將跳過循環體的執行,并繼續執行 while 循環之后的下一條語句。
示例:
在下面這個例子中,while 循環會重復執行,直到變量 i 的值達到5(不再小于5),此時條件表達式 i < 5 變為假,循環結束。循環體內的 printf 語句用于打印變量i的當前值,而 i++ 語句則負責更新變量 i 的值,以確保循環能夠正常結束。
#include <stdio.h> int main() { int i = 0; while (i < 5) { // 條件表達式 printf("%d\n", i); // 循環體 i++; // 更新條件表達式中的變量,確保循環能夠在某個點結束 等價于 i += 1 } return 0;
}
輸出結果如下所示:
?下面來看使用 while 語句計算1到100之間所有整數之和的累加例子,如下例所示:
#include <stdio.h>int main() {int i=1,total=0;while( i <= 100 )//不能在 while 后面加分號{total += i;i++;//循環內要有使循環趨近于假的操作}printf("%d\n",total); // 5050return 0;
}
3.3 注意事項
3.3.1 while 后面不能加分號
在C語言中,如果在 while 語句的條件表達式后面直接加上一個分號(;),那么這個分號實際上被視為 while 循環的“空語句”體。這意味著 while 循環將無限地評估條件表達式,但由于循環體為空(即不執行任何操作),所以程序看起來像是沒有做任何事情,但實際上它正忙于不斷地檢查條件表達式的值,從而導致了所謂的 “空循環” 或 “無限(死)循環”。
錯誤的示例:
int i = 0;
while (i < 5); { // 注意這里的分號 printf("%d\n", i);
}
// 這段代碼會導致無限循環,因為 while 循環的“體”實際上是空的,
// 而下面的花括號塊則與 while 循環無關,會獨立地執行一次(如果它不是位于函數之外的話),
// 但這通常不是我們想要的結果。
正確的做法:
int i = 0;
while (i < 5) { printf("%d\n", i); i++; //循環內要有使循環趨近于假的操作
}
// 這段代碼正確地使用了while循環,循環體會在條件為真時執行。
3.3.2?使用花括號括起循環體
即使while循環體內只有一條語句,也建議使用花括號 {} 將其括起來。這有幾個好處:
- 清晰性:花括號明確地標出了循環體的開始和結束,使得代碼更加易于閱讀和理解。
- 可擴展性:隨著程序的發展,你可能需要在循環體內添加更多的語句。如果一開始就使用了花括號,那么添加新語句時就不需要改變循環的結構。
- 避免錯誤:如果不使用花括號,并且后來嘗試在“單條語句”的循環體內添加更多語句,而沒有意識到原來的語句已經被視為循環體,那么這些新添加的語句將不會被循環控制,這可能會導致難以發現的錯誤。
推薦的做法:
int i = 0;
while (i < 5) { printf("%d\n", i); i++; //循環內要有使循環趨近于假的操作// 如果將來需要添加更多語句,這里可以直接添加,而不需要改變循環的結構。
}
4 do-while 循環
do-while 循環是C語言中另一種基本的循環控制結構,與 while 循環相似,但它有一個關鍵的區別:do-while 循環至少會執行一次循環體內的語句,即使條件表達式的值在第一次評估時就為假。這是因為 do-while 循環的控制結構是先執行循環體,然后再評估條件表達式。【先執行后判斷】
4.1 一般形式
do { // 循環體(至少執行一次)
} while (表達式);
- 循環體:包含了一組在循環中重復執行的語句。在do-while?循環中,這些語句至少會被執行一次。
- 表達式:這是一個條件表達式,其值在每次循環體執行完畢后被評估。如果條件為真(非零),則循環繼續;如果條件為假(零),則循環結束。
工作原理:
- 執行循環體內的語句。
- 評估條件表達式的值。
- 如果條件為真,則返回步驟1并重復執行循環體。
- 如果條件為假,則退出循環,繼續執行?do-while 循環之后的語句。
示例:
#include <stdio.h> int main() { int i = 0; do { printf("%d\n", i); i++; } while (i < 5); return 0;
}
在這個例子中,do-while 循環會首先執行循環體內的語句,即打印變量 i 的當前值,并將 i 的值增加1。然后,它評估條件表達式 i < 5。由于初始時 i 的值為0,小于5,因此條件為真,循環繼續執行。這個過程會一直重復,直到 i 的值達到5,條件表達式變為假,循環結束。
4.2?注意事項
與?while 循環不同,do-while?循環至少會執行一次循環體,即使條件表達式的初始值為假。
為了避免無限循環,必須在循環體內包含某種更新條件表達式的操作,以確保在某個時刻條件會變為假。
在某些情況下,當你知道循環體至少需要執行一次時,do-while?循環是更好的選擇。然而,在大多數情況下,while 循環和?for 循環(特別是后者,因為它更靈活)是更常用的循環控制結構。
5 for 循環
C 語言中的 for 循環語句使用最為靈活,不僅可以用于循環次數已經確定的情況,而且可以用于循環次數不確定而只給出循環結束條件的情況,它完全可以代替 while 循環語句。
5.1 一般形式
for (初始化表達式; 循環條件表達式; 更新表達式) { // 循環體
}
初始化表達式:在循環開始前執行,通常用于初始化一個或多個循環控制變量。它只執行一次。
循環條件表達式:在每次循環開始前求值。如果表達式的結果為真(非零),則執行循環體;如果為假(零),則退出循環。這是決定是否繼續循環的關鍵。
更新表達式:在每次循環體執行完畢后執行,通常用于更新或遞增/遞減循環控制變量。
循環體:當循環條件為真時,重復執行的語句塊。
5.2?執行過程
(1)初始化表達式執行
- 在循環開始前,首先執行初始化表達式。這通常用于設置循環控制變量的初始值。此表達式只執行一次。
(2)求解循環條件表達式
- 接下來,求解循環條件表達式的值。如果表達式的值為真(即非零),則執行接下來的步驟;如果表達式的值為假(即零),則直接跳過循環體,執行 for 循環之后的語句。
(3)執行循環體
- 如果循環條件表達式的值為真,則執行循環體內的語句。循環體可以包含一條或多條語句,用于完成循環需要重復執行的任務。
(4)求解更新表達式
- 執行完循環體后,求解更新表達式。這通常用于更新循環控制變量的值,為下一次循環迭代做準備。更新表達式執行完畢后,控制流回到第(2)步。
(5)轉回第(2)步繼續執行
- 控制流回到第(2)步,再次求解循環條件表達式的值。如果條件仍為真,則重復執行第(3)步和第(4)步;如果條件為假,則跳出循環。
(6)循環結束,執行for語句下面的語句
- 當循環條件表達式的值變為假時,循環結束。此時,程序將執行 for 循環之后的語句。
示例1:
#include <stdio.h> int main() { for (int i = 1; i <= 5; i++) { printf("%d\n", i); } return 0;
}
在上面這個例子中,i = 1 是初始化表達式,它設置循環控制變量 i 的初始值為1。i <= 5 是循環條件表達式,只要i的值小于或等于 5,循環就會繼續。i++ 是更新表達式,它在每次循環迭代結束時將i的值增加1。循環體是 printf 語句,用于打印當前的 i 值。
示例2:
#include <stdio.h>int main() {int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}printf("1 到 100 之間的所有整數之和為: %d\n", sum);return 0;
}
我們首先初始化一個變量 sum 為 0,然后通過 for 循環從 1 迭代到 100。在每次循環中,將當前的整數 i 累加到 sum 中。最后,打印出求和的結果。
5.3 省略寫法
在C語言中,for 循環的初始化表達式、循環條件表達式和更新表達式都是可選的,但兩個分號(;)必須保留以維持語法結構。
5.3.1?省略初始化表達式
當省略初始化表達式時,循環變量(如果有的話)需要在循環外部進行初始化。
int i = 0; // 外部初始化
for (; i < 5; i++) { printf("%d\n", i);
}
這里,i 在for 循環外部被初始化為 0 ,循環條件檢查 i 是否小于5,如果是,則執行循環體,并在每次迭代后通過更新表達式 i++ 來增加i的值。
5.3.2?省略循環條件表達式
如果省略循環條件表達式,那么循環將變成無限循環,除非在循環體內部有某種機制(如break語句)來跳出循環。
int i = 0;
for (; ; i++) { if (i >= 5) break; // 使用break語句來跳出循環 printf("%d\n", i);
}
在這個例子中,由于循環條件表達式被省略了,所以循環會一直執行,直到遇到 break 語句。
5.3.3?省略更新表達式
當省略更新表達式時,循環控制變量的值不會在每次迭代后自動更新。這通常意味著需要在循環體內部手動更新循環控制變量的值,或者依賴于循環體內部的其他邏輯來確保循環能夠正確終止。
int i = 0;
for (; i < 5; ) { printf("%d\n", i); i++; // 手動更新循環控制變量
}
在這個例子中,盡管更新表達式被省略了,但我們在循環體的末尾手動增加了i的值,以確保循環能夠正確終止。
5.3.4?省略所有表達式
for (;;) { // 死循環即無限循環,直到遇到break或其他跳出循環的語句
}
這種形式的 fo r循環通常用于需要持續運行直到某個條件滿足(并在循環體內檢查該條件)的情況。
省略 for 循環中的表達式可以提供靈活性,但也需要開發者更加小心地管理循環的控制流程,以避免無限循環或意外的程序行為。在實際編程中,建議僅在確實需要時才省略這些表達式,并確保循環的邏輯是正確的。
建議都寫上,直觀明了~
5.4 注意事項
5.4.1?for后面不能加分號
如果你在 for 循環的圓括號之后直接加了一個分號(;),那么你就定義了一個空的循環體。這意味著循環體將不會包含任何代碼,而更新表達式(如果有的話)仍然會在每次循環時執行。
for (int i = 0; i < 10; i++) { // 正確的循環體
} // 錯誤的用法,循環體為空
for (int i = 0; i < 10; i++); { // 這段代碼實際上不在for循環內 printf("%d\n", i); // 注意:這里i在循環結束后才可用,但在這個上下文中可能產生編譯錯誤或未定義行為
} // 更常見的錯誤可能是這樣的
for (int i = 0; i < 10; i++); // 空的for循環,但分號結束
printf("%d\n", i); // 這段代碼在for循環之后執行,i的值是10(如果循環條件正確)
5.4.2?循環條件的正確性
確保循環條件能夠準確地控制循環的開始、結束和迭代次數,避免出現無限循環或過早結束循環的情況。
// 錯誤示例:循環條件錯誤導致無限循環
for (int i = 0; i < 10; i--) {// 循環體
}
6 三種循環的選擇
6.1 for循環
適用情況:當你知道循環需要執行的確切次數時,for循環是最佳選擇。它也適用于需要初始化變量、檢查條件和更新變量的場景。
優點:for循環的結構清晰,將初始化、條件和更新表達式集中在一起,使得循環的邏輯一目了然。
使用建議:在大多數需要計數或迭代固定次數的情況下,使用for循環。
6.2 while循環
適用情況:當你不知道循環需要執行的確切次數,但有一個持續檢查的條件時,while循環是合適的。
優點:while循環提供了更大的靈活性,因為它不需要在循環開始前初始化變量或在每次迭代后更新變量。
使用建議:在需要基于條件持續執行循環,且循環次數不確定或條件與循環控制變量的更新不直接相關時,使用while循環。
6.3?do-while循環
適用情況:do-while循環與while循環類似,但它至少會執行一次循環體,無論條件是否為真。
優點:確保循環體至少被執行一次,這在某些情況下是有用的,比如當你需要至少執行一次操作來初始化或檢查某些條件時。
使用建議:在需要至少執行一次循環體,然后基于條件決定是否繼續執行時,使用do-while循環。
?for?循環的可讀性要比?while?循環的好,所以能使用?for?循環時不要強制改為?while?循環。
7?continue?語句
C 語言中的 continue 語句是一種流程控制語句,它用于跳過當前循環迭代中 continue 語句之后的剩余代碼,并立即開始下一次循環迭代(如果有的話)。這意味著continue語句僅影響它所在的循環的當前迭代,而不會影響循環的繼續執行或退出。
continue語句可以用在for循環、while循環和do-while循環中,但不能用在函數外部或任何其他控制結構(如if語句)中。
7.1 語法及示例
continue;
使用場景:continue 語句通常用于在循環體中遇到某些特定條件時,跳過當前迭代中的剩余部分,直接開始下一次迭代。這可以用于忽略某些不需要處理的元素或情況。
示例:對1到100之間的所有奇數進行求和
#include <stdio.h> int main() { int sum = 0; // 用于存儲奇數和的變量 for (int i = 1; i <= 100; i++) { if (i % 2 == 0) { continue; // 如果i是偶數,則跳過本次循環的剩余部分 } sum += i; // 如果是奇數,則將其加到sum上 } printf("1到100之間的奇數和為: %d\n", sum); //2500return 0;
}
7.2 注意事項
continue 語句只能在循環體內使用!
在 while 和 do-while 循環中使用continue語句時,需要特別小心,以確保不會跳過更新循環條件或執行使循環趨近于結束的必要語句。如果這樣做了,就可能導致無限循環或不符合預期的行為。
7.2.1 對于while循環
在while循環中,循環條件是在每次迭代之前檢查的。如果 continue 語句跳過了更新循環控制變量的代碼,并且循環條件沒有在其他地方被更新為可能使循環結束的值,那么循環可能會無限進行下去。
示例(錯誤用法):
int i = 0;
while (i < 10) { if (i % 2 != 0) { continue; // 跳過奇數 } printf("%d ", i); i++; // 確保循環條件有機會變為假
}
正確的 while 循環示例:
int i = 0;
while (i < 10) { if (i % 2 != 0) { i++; //這里也要來一下,防止continue跳過了continue; // 跳過奇數 } printf("%d ", i); i++; // 確保循環條件有機會變為假
}
7.2.2 對于do-while循環
在do-while循環中,循環體至少執行一次,然后檢查循環條件。如果 continue 語句被用來跳過更新循環控制變量的代碼,并且循環條件在循環體內沒有在其他地方被更新為可能使循環結束的值,那么循環也可能繼續執行,直到外部干預(如break語句或程序的其他部分)。
do-while循環的示例:
#include <stdio.h>int main() {int i = 0;do {if (i % 2 != 0) {i++;continue; // 跳過奇數}printf("%d ", i);i++; // 確保循環條件有機會變為假} while (i < 10);return 0;
}
8?break?語句
C 語言中的 break 語句是一種流程控制語句,它用于立即退出它所在的循環(for、while、do-while)或?switch?語句。當執行到 break 語句時,程序會跳過當前循環體中break語句之后的所有語句(如果有的話),并且跳出循環或 switch 語句,繼續執行循環或 switch 之后的語句。
8.1 語法及示例
break;
示例:程序從1開始累加,當累加的和大于2000時,結束 for 循環,并打印此時 total 的值和循環變量 i 的值。
#include <stdio.h>int main() {int i = 1; // 循環變量初始化int total = 0; // 累加和初始化for (; i <= 1000; i++) { // 注意這里去掉了i的初始化,因為我們在循環外已經初始化了itotal += i; // 累加if (total > 2000) { // 檢查累加和是否大于2000break; // 如果是,則退出循環}}// 打印結果printf("當累加的和大于2000時,i的值為:%d\n", i); // 63printf("此時,累加和total的值為:%d\n", total); //2016return 0;
}
8.2 注意事項
8.2.1?只會跳出當前所在的最內層結構
在嵌套的循環或 switch 語句中使用 break 時,它只會跳出當前所在的最內層結構,而不是所有的嵌套結構。如果想要跳出多層嵌套,可能需要額外的邏輯控制。
for (int i = 0; i < 5; i++) {for (int j = 0; j < 5; j++) {if (j == 3) {break; // 只會跳出內層的 for 循環,而不是外層的}}
}
8.2.2 適用范圍
break 通常用于 switch 語句和循環結構(如 for、while、do-while)中。在其他地方使用可能會導致語法錯誤或不符合預期的邏輯。
在switch語句中的使用(后期課程學習,這里先引入下)
在 switch 語句中,break 語句用于防止代碼自動“落入”下一個 case 塊。如果沒有 break 語句,一旦某個 case 的條件滿足,從該 case 開始到 switch 語句結束(或遇到下一個 break 語句)之間的所有 case 塊都會被執行,這通常不是預期的行為。
#include <stdio.h> int main() { char grade = 'B'; switch(grade) { case 'A': printf("Excellent!\n"); break; case 'B': case 'C': printf("Well done\n"); break; case 'D': printf("You passed\n"); break; case 'F': printf("Better try again\n"); break; default: printf("Invalid grade\n"); } return 0;
}
9 小節判斷題
1、關系表達式或者邏輯表達式最終的結果都是 1 或者 0 ?
A 正確? ? ? ? ?B 錯誤
答案:A
解釋:正確的,這個需要記住。
2、if 可以單獨使用,不一定非要有 else ?
A 正確 ????????B 錯誤
答案:A
解釋:if 判斷可以單獨使用,這個需要記住。
3、 else 可以單獨使用,不一定非要有 if ?
A 正確???????? B 錯誤
答案:B
解釋:else 必須和 if 配對使用,不可以單獨存在,這是語法要求。
4、代碼編寫 int a=5; if(3<a<10) 這種編寫方式是否正確 ?
A 正確???????? B 錯誤
答案:B
解釋:在程序中是錯誤的。首先,無論 a 是大于 3 還是小于 3,對于 3<a 這個表達式只有 1 或 0 兩種結果。由于 1 和 0 都是小于 10 的,所以無論 a 的值為多少,這個表達式的值始終為真,因此在判斷變量 a 是否大于 3 且同時小于 10 時,要寫成 a>3 && a<10 ,這才是正確的寫法。
5、 while(i<10); 這條語句沒有問題,程序可以正常運行?
A 正確 ????????B 錯誤
答案:B
解釋:當在 while 語句的小括號后面加分號后,會造成死循環。
6、for(:;) 語句可以這么寫,把 3 個表達式都省略,只剩余兩個分號?
A 正確 ????????B 錯誤
答案:A
解釋:for 語句中的兩個分號是不可以省略的,其他的表達式都可以省略,但是我們一般不會省略表達式,因為 for 的 3 個表達式使用起來非常方便
7、continue 語句的作用為結束本次循環,即跳過循環體中下面尚未執行的語句,接著進行是否執行下一次循環的判斷?
A 正確 ????????B 錯誤
答案:A
解釋:這是 continue 的作用,需要記住,在 while 循環中使用 continue 要小心, continue 之前要有讓 while 循環判斷趨近于假的操作,避免死循環。
8、 break 語句的作用是結束整個循環過程?
A 正確 ????????B 錯誤
答案:A
解釋: break 語句是結束整個循環,和 continue 的區別一定要清晰,理解可以再次看視頻,通過我們視頻里的實例清晰理解。
10 OJ 練習
10.1?課時4作業1
這道題主要是練習如何通過循環操作,將一個整型數逆置,我們判斷逆置后的整型數如果和
最初的數相等,那么它就是對稱數,如果不相等,就不是對稱數。
#include <stdio.h>int main() {// inputNumber : 用于存儲輸入的數字// reversedNumber : 用于存儲反轉后的數字,必須初始化,后需要對其做乘10處理// tempNumber : 臨時存儲輸入的數字,用于后續比較int inputNumber,reversedNumber = 0, tempNumber;// 從用戶處獲取輸入的數字scanf("%d", &inputNumber);// 先把輸入的數據保護好tempNumber = inputNumber;// 這個循環用于將輸入的數字反轉while (inputNumber) {reversedNumber = reversedNumber * 10 + inputNumber % 10; // 將當前數字的個位添加到反轉數字中,并乘以 10 為下一位做準備inputNumber /= 10; // 去除當前數字的個位}// 判斷輸入的數字是否與反轉后的數字相等if (tempNumber == reversedNumber) {printf("yes"); // 是對稱數,輸出"yes"} else {printf("no"); // 不是對稱數,輸出"no"}return 0;
}
10.2?課時4作業2
這個題目主要考察的是 for 循環的使用。
#include <stdio.h>int main() {int number,factorial = 1; // 初始化階乘結果為1 // 讀取用戶輸入的數scanf("%d", &number);// 使用for循環計算階乘 for(int i = 1; i <= number; i++) {factorial *= i; // 累乘計算階乘 }// 輸出結果 printf("%d\n", factorial);return 0;
}
10.3?課時4作業3
這個題目考察的是多層循環的使用,有 4 種類型鈔票,那么我們選擇 4 層循環,只需在最
內層的循環判斷鈔票組合后的值為 100,就可以完美解決這個問題。注意控制每一層循環的
邊界,不要過大,當然如果每個邊界都寫 40,在 OJ 也可以 AC。
10元紙幣的數量不能為0(至少1張),且不能超過9張(否則總金額會超過100元)? 。
5元紙幣的數量也不能為0(至少1張),(100-10-2-1) / 5=17,最多17張。
2元紙幣的數量也不能為0(至少1張),最多37張。
1元紙幣的數量也不能為0(至少1張),最多37張。
所以,四層循環如下:
#include <stdio.h>int main() {int counter = 0; // 用于計數滿足條件的換法// 外層循環:10元紙幣的數量,從1到9張for (int i = 1; i <= 9; ++i) {// 注釋:10元紙幣的數量不能為0(至少1張),且不能超過9張(否則總金額會超過100元)// 第二層循環:5元紙幣的數量,從1到17張for (int j = 1; j <= 17; ++j) {// 注釋:5元紙幣的數量也不能為0(至少1張),(100-10-2-1)/5=17// 第三層循環:2元紙幣的數量,從1到37張for (int k = 1; k <= 37; ++k) {// 注釋:2元紙幣的數量也不能為0(至少1張),最多37張// 第四層循環:1元紙幣的數量,從1到37張for (int l = 1; l <= 37; ++l) {// 注釋:1元紙幣的數量也不能為0(至少1張),最多37張// 檢查當前組合是否滿足總金額為100元和總張數為40張的條件if (100 == i * 10 + j * 5 + k * 2 + l * 1 && i + j + k + l == 40) {counter++; // 如果滿足條件,則計數器加1}}}}}// 輸出滿足條件的換法總數printf("%d\n", counter);return 0;
}