C語言進階教程之循環(huán)語句缺陷詳析
前言
你是否也有過下面的體會?
為什么剛開始學(xué)習(xí)C語言時很喜歡用for循環(huán)語句,但逐漸發(fā)現(xiàn)有經(jīng)驗的工程師都在用while和do-while循環(huán)(看過內(nèi)核代碼的小伙伴應(yīng)該也注意到這點了)?
在剛開始寫循環(huán)語句時總分不清什么時候用for,什么時候用while,什么時候又該使用do-while;剛把這些問題搞清楚了,覺得已經(jīng)熟練掌握了所有循環(huán)語句的使用,但又時不時遇到一個新的問題——總得在循環(huán)語句中,甚至是循環(huán)語句前和循環(huán)語句后添加代碼,調(diào)整語句順序,否則最終的邏輯就不正確,甚至是出現(xiàn)指針的解引用錯誤。
當(dāng)遇到這些問題時,你是否懷疑過C語言的循環(huán)語句是自帶缺陷的?下面就讓我們一起找出困擾我們編程的幕后黑手吧~~
1 循環(huán)語句的三要素
實現(xiàn)一個循環(huán)語句的三要素是:
- A. 判斷:判斷退出條件是否滿足,如果滿足則退出循環(huán);如果不滿足則循環(huán)繼續(xù)。
- B. 執(zhí)行:執(zhí)行需要循環(huán)的內(nèi)容;內(nèi)容中一般都會引用循環(huán)變量,否則循環(huán)就是無差別的。
- C. 移動:移動循環(huán)變量,否則退出條件永遠(yuǎn)無法滿足,循環(huán)就演變成了死循環(huán),這也是初學(xué)者很容易落的。
根據(jù)上述三個要素的執(zhí)行順序,可以得到下述6種排列組合。
編號 | 順序 |
---|---|
1 | A -> B -> C |
2 | A -> C -> B |
3 | B -> C -> A |
4 | C -> B -> A |
5 | B -> A -> C |
6 | C -> A -> B |
你所編寫的程序中都逃不出以上這六種排列組合,下面我們對其一一進行剖析。
2 使用不同循環(huán)語句實現(xiàn)六種排列組合
2.1 第一種排列(ABC)
這種順序是我們最最熟悉的,也是最常見的。實現(xiàn)起來并不復(fù)雜,也是C語言循環(huán)語句最擅長處理的情況。
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)ABC */ for (; A; C) { B; }
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)ABC */ while (A) { B; C; }
2.2 第二種排列(ACB)
這種順序我們就不是經(jīng)常見到了,所以,for語句對它的支持就不是那么友好了,但是while語句沒有受到任何影響。
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)ACB */ for (; A; ;) { C; B; }
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)ACB */ while (A) { C; B; }
2.3 第三種排列(BCA)
對于這種排列,for語句徹底沒脾氣了,while語句也蔫兒了,do-while語句可以大顯身手了。
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)BCA */ for (B, C; A; C;) { /*可讀性變得很差,也有很多重復(fù)代碼*/ B; }
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)BCA */ B; /*已經(jīng)需要在while語句外額外加重復(fù)代碼了*/ C; while (A) { B; C; }
使用do-while語句實現(xiàn)
/* 使用do-while語句實現(xiàn)BCA */ do { B; C; }while (A); /*do-while就是為此而生?。磥碓O(shè)計該語句的老前輩已經(jīng)仔細(xì)考慮過該排列了)*/
2.4 第四種排列(CBA)
這種排列跟上一種類似。不過對for語句就更不友好了。
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)CBA */ for (C, B; A; C,B;) /*這種形式看似一行就處理結(jié)束了,但是真實情況是B的內(nèi)容會很多*/
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)CBA */ C; /*重復(fù)代碼*/ B; while (A) { C; B; }
使用do-while語句實現(xiàn)
/* 使用do-while語句實現(xiàn)CBA */ do { C; B; }while (A); /*do-while語句默默地說:“這里才是我的戰(zhàn)場”。*/
2.5 第五種排列(BAC)
對于這種排列,C語言的循環(huán)語句們心里都在想,這是什么鬼地方,沒見過啊~~
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)BAC */ for (B; A; ;) { /*有重復(fù)代碼*/ C; B; }
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)BAC */ B; /*有重復(fù)代碼*/ while(A) { C; B; }
使用do-while語句實現(xiàn)
它說它不在家,讓我們?nèi)フ襜reak。
使用while-break語句實現(xiàn)
/* 使用while-break語句實現(xiàn) */ while (1) { B; if (!A) break; C; }
2.6 第六種排列(CAB)
這種排列和第五種類似,不使用break仍然無法解決代碼重復(fù)問題。
使用for語句實現(xiàn)
/* 使用for語句實現(xiàn)CAB */ for (C; A; C) { B; }
使用while語句實現(xiàn)
/* 使用while語句實現(xiàn)CAB */ C; while (A) { B; C; }
使用while-break語句實現(xiàn)
/* 使用while-break語句實現(xiàn)CAB */ while (1) { C; if (!A) break; B; }
3 什么時候用for循環(huán)語句
通過上面的實驗和摸索,我們發(fā)現(xiàn)for語句最適合的場景就是第一種排列(ABC)的場景。在應(yīng)用與其他場景時要么就退化為while,要么就束手無策了。
這就是for語句的缺陷之所在。
所以,你去看Linux內(nèi)核或者其他大型項目,其中的for語句都是比較少的,你所見到的基本都長成下面這兩種樣子。
/* for循環(huán)的第一種應(yīng)用范式 */ #define MAX 100 int i; for (i = 0; i < MAX; ++i) { /* do somthing you like. */ }
我是分割線。。。
/* for循環(huán)的第二種應(yīng)用范式 */ for (;;) { /* do somthing you like. */ }
第二種應(yīng)用范式一般都是用在線程死循環(huán)中,當(dāng)然死循環(huán)使用while(1)也可以,只能說是大家都這么用習(xí)慣了而已,你可以選擇自己喜歡的方式。
4 什么時候用while循環(huán)語句
while語句適用于第一種排列(ABC)和第二種排列(ACB)場景。
這種場景的特點是——A在最開始執(zhí)行。
5 什么時候用do-while循環(huán)語句
do-while語句適用于第三種排列(BCA)和第四種排列(CBA)場景。
這種場景的特點是——A在最后執(zhí)行 。
6 其他情況
其他情況包括第五種排列(BAC)和第六種排列(CAB)場景,以及其他更復(fù)雜的場景。
這種場景的特點是——A在中間執(zhí)行。
這種情景一般就采用whie-break語句來cover了。其實,該語句可以cover住所有場景。
愛刨根問題的同學(xué)可能會問,怎么會有這種場景呢?真的有需求么?
那我在此給出一個CABC真實場景的小例子吧,起到拋磚引玉的作用。
/* 重點關(guān)注外層循環(huán);關(guān)注pstr指針變量 */ while(1){ pstr = find_cmd(format_str, pstr); /*C[移動]:這一步會移動pstr指針*/ if (NULL != pstr) /*A[判斷]:在使用前需要先判斷;看指針是否合法,非法則退出循環(huán)*/ { /* B[執(zhí)行]:執(zhí)行開始(讀取字符串內(nèi)容并打印)*/ printf("----------------------------------------------------------------------------\n"); printf("|| name \t| %s \n",pstr->name); printf("|| brief \t| %s \n",pstr->brief); for (i = 0; i < pstr->argc; i++) { if (pstr->argv[i]) printf("|| @ para%d\t| @ %s \n", i, pstr->argv[i]); } printf("----------------------------------------------------------------------------\n"); /* B[執(zhí)行]:執(zhí)行結(jié)束 */ pstr++; /*C[移動]:這一步還是移動,屬于復(fù)雜場景,是六種排列的延伸。。。*/ } else { break; } }
7 總結(jié)
文章已經(jīng)很長了,最后不廢話,直接上表格。
編號 | 順序 | 合適的循環(huán)語句 |
---|---|---|
1 | A -> B -> C | for/while |
2 | A -> C -> B | while |
3 | B -> C -> A | do-while |
4 | C -> B -> A | do-while |
5 | B -> A -> C | while-break |
6 | C -> A -> B | while-break |
x | 復(fù)合場景 | while-break |
到此這篇關(guān)于C語言進階教程之循環(huán)語句缺陷的文章就介紹到這了,更多相關(guān)C語言循環(huán)語句缺陷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中數(shù)組作為函數(shù)參數(shù)傳入的幾種方式代碼示例
數(shù)組元素和數(shù)組名都可以作為函數(shù)的參數(shù)以實現(xiàn)函數(shù)間數(shù)據(jù)的傳遞和共享,下面這篇文章主要給大家介紹了關(guān)于C++中數(shù)組作為函數(shù)參數(shù)傳入的幾種方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06OpenCV霍夫變換(Hough Transform)直線檢測詳解
這篇文章主要為大家詳細(xì)介紹了OpenCV霍夫變換直線檢測的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12C語言雙指針多方法旋轉(zhuǎn)數(shù)組解題LeetCode
這篇文章主要為大家介紹了C語言雙指針使用多方法旋轉(zhuǎn)數(shù)組題解LeetCode,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02C語言使用單鏈表實現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言使用單鏈表實現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11