今天在前面放了一段伍佰的歌曲《last Dance》,這首老歌最近突然火了是因為一部愛情穿越電視劇《想見你》,劇情還不錯大家感興趣可以看一看,大夥不要天天搞研究,敲代碼,多一點不一樣的生活會有不一樣的精彩,效率也會大大提高。
好了,之前一直都沒有透露自己的聯繫方式,最近一些小夥伴私信給我說,有問題在公眾號私信我比較麻煩而且有時候也沒注意訂閱號,希望我能夠提供個人微信。確實最近發現私信的給我的圖片有時候打不開,為了更好的交流這裡公布一下個人的微信號,大家可以添加一下,研究、學習、生活上都可以跟我交流,我也可以準備酒,等待著你的故事:
好了,要進入今天的主題了,今天我們要討論的是C語言中相對比較冷門的知識關鍵字goto!
關鍵字goto從字面的意思就是"去哪裡"的意思,專業一點的話表示無條件跳轉的意思(有學過彙編的小夥伴應該會覺得非常像jump指令),在C語言中的使用格式是:goto label,表示跳轉到label的位置,並且我們的label一般都寫在語句的開頭,寫成label:的形式。(下面一個小例子來簡單介紹用法)int main(int argc, char *argv[]) {
//無條件跳轉到標籤處
goto thelastBug;
printf("未知bug\n");
//標籤定義
thelastBug:
printf("最後一個bug\n");
return 0;
}
1)goto label;後面的分號一定得打。(個人經常忘記,這裡提醒一下各位)
2)goto只能在函數內部無條件跳轉,不能從一個函數跳轉到另外一個函數。
3)label:的標識在使用goto語句的前後均可,不遵循先定義後使用。
4)label的作用域在函數內部,不同函數之間可以定義相同的label。
(上面的幾點注意項大家有時間可以在電腦上實驗下)
對於goto的使用程序語言界算是爭議不斷,並且大部分大學C語言老師在講到到goto這關鍵字的時候一般都會叫大家慎用goto關鍵字,甚至有部分老師一棍子拍死「禁止使用goto關鍵字」。個人覺得一棍子打死終究不合適,慎用比較說得過去點。如果說禁止使用那為什麼還要在C語言標準中定義呢?乾脆直接剔除算了。有句話說得好,"存在即合理"。 我們在高中學習算法的時候應該畫過基本的結構圖,三大基本的程序結構分別是:順序結構、分支結構和重複結構,這個三種結構就能夠創造出所有的邏輯結構,那麼我們C語言就是順序執行的表示順序結構;if、switch等表示分支結構;while、for等結構表示的是重複結構。可以說我們不用goto語句也能編寫出我們想要實現的程序。/**********************************
* Fucion: main
* Descri: if+goto 模擬for語句
**********************************/
int main(int argc, char *argv[]) {
//循環變量定義
int i = 0;
i = 0;
Loop:if(i > 5){goto LoopEnd;}i++;
//for(i= 0;i<5;i++)
//{
printf("%d\n",i);
goto Loop;
//}
LoopEnd:
printf("最後一個bug\n");
return 0;
}
其他的重複語句也可以由分支+goto模擬,這裡就不再書寫代碼了,只是說用模擬循環的方式似乎書寫上不是很美觀。所以我覺得並不是goto不好用,而是怕大家濫用,導致對程序的把控力的下降。 那麼我們再深入一點看待goto語句,我上面說了該關鍵字非常的靈活,其實goto本身的功能是非常簡單的,就是一個跳轉到所定義的標籤label位置,靈活的地方在於label可以在一個函數內部每一句的開頭都可以定義。所以我們要控制goto為我們所用主要就是控制label的使用問題,後面我們會有例子教大家怎麼控制label,所以goto語句還是一個非常有潛力的關鍵字,對於設計巧妙高效的算法會非常有用!所以個人覺得只要對goto語句的使用加以管束為我們開發服務,這未嘗不是一件好事。我們讀過linux相關代碼的小夥伴會發現goto語句的使用無處不在,首先我截取了uboot1.1.6中的一部分代碼來欣賞一下(畢竟uboot也是大佬寫的):
第一張是一個函數的前半部分,第二張為該函數末尾,中間代碼還有非常多這樣的語句。程序大體的意思是:打開一個文件,然後對該文件一系列操作,一旦操作不成功就會goto到error標籤,然後關掉該文件,否則如果都執行成功了就會return 1.表示成功。我們都知道break僅僅只能跳出當前循環,如果遇到多層循環需要跳出的問題,就需要每個循環都需要break一下,並且還需要內層循環傳遞相關信號讓外層循環break掉,從而退出多層循環,這樣做實在有點麻煩,而且代碼結構也不好看,那麼有些小夥伴就會問那我直接return掉就好了,我們來看一下下面的代碼你就會有自己的決定了:
/**********************************
* Fucion: main
* Descri: goto跳出多層循環
**********************************/
int main(int argc, char *argv[]) {
int i = 0,j = 0,k = 0;
for(i = 0 ;i < 10;i++)
{
for(j = 0 ;j < 10;j++)
{
for(k = 0 ;k < 10;k++)
{
//if(條件不滿足)
//goto ERROR;
}
//if(條件不滿足)
//goto ERROR;
}
//if(條件不滿足)
//goto ERROR;
}
return 1;
ERROR:
//相關資源釋放
printf("最後一個bug\n");
return 0;
}
/**********************************
* Fucion: main
* Descri: return跳出多層循環
**********************************/
int main(int argc, char *argv[]) {
int i = 0,j = 0,k = 0;
for(i = 0 ;i < 10;i++)
{
for(j = 0 ;j < 10;j++)
{
for(k = 0 ;k < 10;k++)
{
//if(條件不滿足)
//相關資源釋放
//return 0;
}
//if(條件不滿足)
//相關資源釋放
//return 0;
}
//if(條件不滿足)
//相關資源釋放
//return 0;
}
printf("最後一個bug\n");
return 1;
}
這裡僅僅代碼個人的使用觀點:
1)上面兩個例子中我們使用goto是可以借鑑的,對程序的效率和美觀有一定的效果;
2)對於一般的程序goto語句的功能儘量簡單,便於分析和代碼的整潔,如果不能帶來較大的優勢還是儘量少用;
3)個人平時研究控制理論,對於任何事物覺得要麼是發散、要麼是收斂比較好分析處理問題,對于震蕩問題相對比較麻煩,所以對於如下圖2種goto的使用情景我是推薦的,前面說了只要我們控制好goto的靈活度就能夠為我們服務,那麼我們只需要規定在一個函數中其只是單向跳轉,我們對程序的把控能力就大大提高了。
好了,今天的內容就到這裡吧,看完這個文章希望大家能夠有點收穫吧,也希望大家能幫忙傳播傳播,"再看"多點幾個,大家的認可都是我堅持寫作的動力源泉,寫作這條路上還是需要大家多多陪伴。
感謝關注公眾號:"最後一個bug",我們下期見!