網站首頁 編程語言 正文
一、do…while()循環
1. 圖示流程
???????從上面圖示 do…while() 語句流程中可以看出,do…while() 語句會先進入循環體執行里面的內容,然后再進行條件判斷,當條件為真,就繼續執行循環體的內容,當條件為假就退出do…while() 語句。也就是說 do…while() 語句 最少會執行一遍循環體里面的內容。
2. 代碼流程
do {
? ? 語句塊
} while (表達式);
??????? do…while() 語句的代碼流程也很簡單,程序執行到 do…while() 語句的時候,會先執行語句塊(也叫循環體)中的內容,執行完一次后,就會判斷表達式的內容是真還是假,如果是真,那么就繼續執行語句塊的內容,如果是假,那么就不再執行語句塊的內容,而是退出該循環。在寫 do…while() 語句的時候 while 后面那個分號千萬不能掉了,這點新手尤其要注意
3. 示例代碼1到100求和)
源代碼:
#include <stdio.h>
int main()
{
int i = 0, sum = 0;
do {
sum += i;
i++;
} while (i <= 100);
printf("sum = %d\n", sum);
return 0;
}
運行結果:
sum = 5050
二、while()循環
1. 圖示流程
??????? while() 循環語句會先判斷條件,當條件為真的時候才會執行循環體,當條件為假的時候直接就退出了循環體。也就是說,while() 語句循環體里面的內容可能一次都不會被執行,這就是 while() 語句和 do…while() 語句最大的區別。
2. 代碼流程
while (表達式) {
?? ?語句塊
}
???????while() 循環語句的代碼流程也很簡單,就是先判斷表達式的內容,當表達式為真的時候,就執行語句塊的內容,語句塊中的內容執行完了后又會判斷表達式的值,直到表達式的值為假才會跳出語句塊中。
3. 示例代碼(1到100求和)
源代碼:
#include <stdio.h>
int main()
{
int i = 0, sum = 0;
while (i <= 100) {
sum += i;
i++;
}
printf("sum = %d\n", sum);
return 0;
}
運行結果:
sum = 5050
三、for()循環
1. 圖示流程
???????for() 循環的圖示代碼流程和 while() 循環的圖示代碼流程不能說毫不相干,只能說一模一樣。但是其代碼表現流程有點區別,下面來重點講解下for() 循環的代碼流程。
2. 代碼流程
for (表達式1; 表達式2; 表達式3)?
{
?? ?語句塊
}
???????for() 循環的代碼流程看著表達式挺多的,好像挺復雜,但其實不然,讓我來為大家進行細致講解。
???????for() 循環首先執行表達式1,再執行表達式2,當表達式2的值為真的時候就會執行語句塊的內容,語句塊內容執行完后就會執行表達式3,表達式3執行完,又會跳轉執行表達式2,當表達式2為真,又執行語句塊,相當于循環一直在 表達式2 -> 語句塊 -> 表達式3 之間循環。當表達式2的值為假的時候就會跳出循環。
for() 循環有幾個地方值得大家注意:
(1)表達式1只會在剛進 for 循環的時候執行一次。
(2)在c99及之后的標準中,表達式1處可以定義變量,變量周期在整個for循環中。但是c98不允許這樣做,否則編譯器會報錯。
(3)表達式1、表達式2、表達式3 都可以不寫省略。但是當表達式2省略不寫的時候意味著,編譯器在處理這里的時候這里不為假,從而會執行語句塊。
3. 示例代碼(1到100求和)
源代碼:
#include <stdio.h>
int main()
{
int i = 0, sum = 0;
for (i = 0; i <= 100; i++) {
sum += i;
}
printf("sum = %d\n", sum);
return 0;
}
運行結果:
sum = 5050
四、goto循環
1. 代碼流程
標簽:
goto 標簽;
???????讀到這里可能有讀者會發現,為啥前面都有圖解,goto 語句沒有,是作者不會了嗎?哈哈,其實回答這個問題我只能說是也不是。回答是,是因為確實沒圖解,因為 goto 語句太簡單了,簡單到把我給整不會了。回答不是,是因為簡單到沒必要,哈哈~~
???????其實通過代碼流程就可以看出,goto 語句確實很簡單,就是當程序運行到 goto 那里的時候會跳轉到標簽處接著運行,這種跳轉是無條件跳轉,只要程序運行到 goto,就會跳轉!!!標簽處可以任意命名,命名規則必須遵循C語言標識符命名法。標簽可以寫在 goto 的前面,也可以寫在 goto 的后面,這點不受影響。程序運行到標簽處不會做任何處理,只有goto 才會跳轉到標簽那里,上面兩個標簽的地方名字需要一模一樣。
???????其實說到goto語句,就不得不提一下goto的歷史了,其實在編程的時候大家有個約定俗成的規矩,那就是能不用goto的地方那就不用,為什么會這樣呢,其實就是我上面提到的,goto 語句會無條件跳轉,這點就和其他三個循環不同。了解C語言的人都知道,C語言是面向過程編程,怎么理解面向過程編程呢,其實就是和人一樣,就是現做什么再做什么,人早上起來要先刷牙,再吃早餐。C語言也一樣,要使用變量,就得先定義變量。面向過程就類似這個道理。但是 goto 會無條件跳轉,這就會讓讀代碼的人感覺很混亂,要在代碼中亂跳,并且使用不恰當的話往往達不到自己想要的效果,這也因此使得大家能不用 goto 就盡量不使用 goto。但是在linux內核代碼中,goto 卻會被常常用作一個判錯用途。先看下面示例代碼-2,結合代碼和大家一起講解。
2. 示例代碼-1(1到100求和)
源代碼:
#include <stdio.h>
int main()
{
int i = 0, sum = 0;
loop:
if (i <= 100) {
sum += i;
i++;
goto loop;
}
printf("sum = %d\n", sum);
return 0;
}
運行結果:
sum = 5050
???????寫這個代碼是想告訴大家,都是實現 1 到 100 求和,但是4種循環語句都可以做到,也就是說4種循環之間都可以相互轉換,具體想用哪種循環就全看大家自己的選擇了,但是為了遵循約定俗成的東西,除了特殊場景,大家還是盡量不要使用 goto 語句了。
3. 示例代碼-2
源代碼:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p1, *p2, *p3;
p1 = malloc(10);
if (p1 == NULL) {
printf("malloc failed : 1\n");
goto loop_1;
}
*p1 = 1;
p2 = malloc(20);
if (p2 == NULL) {
printf("malloc failed : 2\n");
goto loop_2;
}
*p2 = 2;
p3 = malloc(30);
if (p3 == NULL) {
printf("malloc failed : 3\n");
goto loop_3;
}
*p3 = 3;
printf("*p1 = %d, *p2 = %d, *p3 = %d\n", *p1, *p2, *p3);
loop_3:
free(p2);
loop_2:
free(p1);
loop_1:
return 0;
}
運行結果:
*p1 = 1, *p2 = 2, *p3 = 3
???????大家看看上面這段代碼,首先申請了10字節空間,如果申請失敗,那么我下面的代碼就沒有執行的必要了,所以直接退出程序。申請成功就會繼續申請20字節空間,假如在這時什么失敗了,那么下面的代碼也同樣沒有執行的必要,然后我也要退出程序,但是在退出程序前,需要將 p1 指向的那塊內存給釋放掉,否則就會造成內存泄漏。如果繼續申請成功,就會再申請30字節空間,如果申請失敗,那么也要退出程序,并且在退出前需要釋放前兩次申請的空間。上面使用 goto 語句有兩大優勢,其一就是可讀性高,操作方便,不然就要在后面每次申請失敗的里面加上釋放前面申請的內存的操作,很明顯如果這樣做,代碼移植效率就會很低,而且假如在中間加了一次申請內存的操作,后面的地方就都要加上出錯釋放內存的步驟。其二就是保持程序退出的地方統一,如果不這樣做,需要在每個出錯的地方加上 return 的操作,代碼可讀性沒有這樣做高。在linux內核代碼種,像上面這樣使用 goto 語句的操作是經常被用到的,很顯然上面這種做法很巧妙,其實在linux內核代碼中還有很多巧妙的操作,如果可以的話,大家可以多讀讀linux源碼,對自己的編碼功底將會有很大的提升的。
原文鏈接:https://blog.csdn.net/liung_/article/details/123146117
相關推薦
- 2022-11-16 通用?HTTP?簽名組件的另類實現方式_實用技巧
- 2022-09-18 C++?STL反向迭代器的實現_C 語言
- 2023-04-03 iOS數據持久化KeyChain數據操作詳解_IOS
- 2023-03-16 redis如何取hash的值_Redis
- 2022-09-15 golang?墻上時鐘與單調時鐘的實現_Golang
- 2022-12-09 Python構造函數與析構函數超詳細分析_python
- 2022-07-02 Python?matplotlib繪圖時指定圖像大小及放大圖像詳解_python
- 2022-04-19 教你如何從正在運行的容器創建?Docker?映像_docker
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支