goto語句

goto語句

goto語句也稱為無條件轉移語句,其一般格式如下: goto 語句標號; 其中語句標號是按標識符規定書寫的符號, 放在某一語句行的前面,標號後加冒號(:)。語句標號起標識語句的作用,與goto 語句配合使用。 如: label: i++; loop: while(x

C# 語言

C語言

統計從鍵盤輸入一行字元的個數。

例如輸入:abcdefghijklmnopqrstuvwxyz

然後回車Enter

輸出:26

本例用if語句和goto語句構成循環結構。當輸入字元不為'\n'時即執行n++進行計數。

然後轉移至if語句循環執行,直至輸入字元為'\n'才停止循環。

彙編語言

goto語句與彙編語言裡面的jmp指令相同,(無條件轉移)

1+2+3........+8+9+10

NASM描述:

mov ax,1

mov bx,0

start:add bx,ax

inc ax

cmp ax,11;比較指令

jzend ;零轉移

jmp start

end:

;

;start: end:是標號

Pascal

格式 goto <標號>;

其中標號需要申請,在程式開頭寫label <標號1>,<標號2>,……;

其中,標號必須為四位以內的正整數。

在該段落內還需要有<標號>:語句 表示將要轉向的方向。

delphi

//Goto語句用在跳轉行號, 可以跳轉到當前結構層內任意位置.

//必須在聲明處用label關鍵字聲明行號.

//由於Goto語句會破壞程式的結構, 不推薦使用.

var

a,b: Integer;

label

X,Y;

begin

if a > b then

goto X

else

goto Y;

X:

WriteLn('a > b');

Y:

WriteLn('b > a');

end;

批處理

使用冒號標記

:start

goto start

按鍵精靈

使用rem做標記,可以用中文

rem 開始

goto 開始

VBA

使用冒號做標記,但是跟批處理的不一樣,冒號在後面

start:

goto start

發展歷程

問題起源:

60年代中期以後,計算機硬體技術日益進步,計算的存貯容量、運算速度和可靠性明顯提高,生產硬體的成本不斷降低。計算機價格的下跌為它的廣泛套用創造了極好的條件。在這種形勢下,迫切要求計算機軟體也能與之相適應。因而,一些開發大型軟體系統的要求提了出來。然而軟體技術的進步一直未能滿足形勢發展的需要,在大型軟體的開發過程中出現了複雜程度高、研製周期長、正確性難以保證的三大難題。遇到的問題找不到解決辦法,致使問題堆積起來,形成了人們難以控制的局面,出現了所謂的“軟體危機”。為了克服這一危機,一方面需要對程式設計方法、程式的正確性和軟體的可靠性等問題進行系列的研究;另一方面,也需要對軟體的編制、測試、維護和管理的方法進行研究,從而產生了程式設計方法學。

goto語句是有害的觀點:

1968年,Edsger Wybe Dijkstra 首先提出“GOTO語句是有害的”論點,向傳統程式設計方法提出了挑戰,從而引起了人們對程式設計方法討論的普遍重視。

goto語句的爭論:

在60年代末和70年代初,關於GOTO語句的用法的爭論比較激烈。主張從高級程式語言中去掉GOTO語句的人認為,GOTO語句是對程式結構影響最大的一種有害的語句,他們的主要理由是:GOTO語句使程式的靜態結構和動態結構不一致,從而使程式難以理解,難以查錯。去掉GOTO語句後,可直接從程式結構上反映程式運行的過程。這樣,不僅使程式結構清晰,便於理解,便於查錯,而且也有利於程式的正確性證明。

持反對意見的人認為,GOTO語句使用起來比較靈活,而且有些情形能提高程式的效率。若完全刪去GOTO語句,有些情形反而會使程式過於複雜,增加一些不必要的計算量。

關於goto語句的解決方法:

1974年,D·E·克努斯對於GOTO語句爭論作了全面公正的評述,其基本觀點是:不加限制地使用GOTO語句,特別是使用往回跳的GOTO語句,會使程式結構難於理解,在這種情形,應儘量避免使用GOTO語句。但在另外一些情況下,為了提高程式的效率,同時又不至於破壞程式的良好結構,有控制地使用一些GOTO語句也是必要的。用他的話來說就是:“在有些情形,我主張刪掉GOTO語句;在另外一些情形,則主張引進GOTO語句。”從此,使這場長達10年之久的爭論得以平息。

後來,G·加科皮尼和C·波姆從理論上證明了:任何程式都可以用順序、分支和重複結構表示出來。這個結論表明,從高級程式語言中去掉GOTO語句並不影響高級程式語言的編程能力,而且編寫的程式的結構更加清晰。

goto語句的結果:

在C/C++等高級程式語言中保留了goto語句,但被建議不用或少用。在一些更新的高級程式語言,如Java不提供goto語句,它雖然指定goto作為關鍵字,但不支持它的使 用,使程式簡潔易讀;儘管如此後來的c#還是支持goto語句的,goto語句一個好處就是可以保證程式存在唯一的出口,避免了過於龐大的if嵌套。

二.可以考慮使用goto的情形

1.從多重循環中直接跳出

很多人建議廢除C++/C的goto語句,以絕後患。但實事求是地說,錯誤是程式設計師自己造成的,不是goto的過錯。goto 語句至少有一處可顯神通,它能從多重循環體中一下子跳到外面,用不著寫很多次的break語句。例如:

for(......){

for(....){

for(.....){

// 如何衝出重重包圍?

}

}

}

break;只能跳出單層的循環,return將整個函式都返回了,沒法再繼續了,顯然也不行,所以我們想到了goto。如果是在陷入了很深層次的循環里想要跳出最外層的循環,用 goto 直接跳出卻比用 break 一個循環一個循環地跳出要好得多。有人甚至形象比喻說:“就像樓房著火了,來不及從樓梯一級一級往下走,可從視窗跳出火坑。” 其實,你可以將 break 和 continue 理解成弱化了的 goto 語句。

2. 出錯時清除資源

如果一個函式有多個出口,則在每個出口處,會產生巨大的退出代碼,如下例一,每個函式只能有一個出口,所有的資源釋放必須放在出口統一解決,那全部使用大括弧,十幾個,幾十個if判斷條件下來,你數數你的大括弧有多深?這種代碼可讀性不好,一旦寫錯了,難於尋找錯誤。所有這些問題,一個goto就解決了。

當程式要分配和清除資源時(像記憶體、或處理字形、視窗、印表機),這種情形下用goto通常是為了複製代碼或清除資源。若遇到這種情況,程式設計師就要掂量是 goto 的缺點令人討厭呢?還是複製代碼那令人頭痛的維護更討厭呢?最後還是認為 goto 的缺點更可忍受。

例子一:不用goto,想想需要申請的指針是10個的話,程式怎么寫?

void Func(void)

{

char* p1=null;

char* p2=null;

char* p3=null;

p1=(char*)malloc(10);

if(!p1) return;

p2=(char*)malloc(10);

if(!p2)

{

free(p1);

p1=null;

return;

}

p3=(char*)malloc(10);

if(!p3)

{

free(p1);

p1=null;

free(p2);

p2=null;

return;

}

……

……

…… //指針使用過程

if(p1)

{

free(p1);

p1=null;

}

if(p2)

{

free(p2);

p2=null;

}

if(p3)

{

free(p3);

p3=null;

}

}

例子二:用goto

void Func(void)

{

char* p1=null;

char* p2=null;

char* p3=null;

p1=(char*)malloc(10);

if(!p1) goto Func_End_Process;

p2=(char*)malloc(10);

if(!p2) goto Func_End_Process;

p3=(char*)malloc(10);

if(!p3) goto Func_End_Process;

……

……

…… //指針使用過程

Func_End_Process:

if(p1)

{

free(p1);

p1=null;

}

if(p2)

{

free(p2);

p2=null;

}

if(p3)

{

free(p3);

p3=null;

}

}

3.可增加程式的清晰度的情況。

若不使用goto語句會使功能模糊,有時候使用goto語句,一眼就看清楚了程式的意圖,可用那些對應的循環break語句等實現的語句段,要想老半天才搞清楚程式意圖的情況,也可考慮使用goto語句。

三.不加限制地使用goto帶來的弊端

1).很明顯,不加限制地使用goto破壞了清晰的程式結構,使程式的可讀性變差,甚至成為不可維護的"麵條代碼"。例如下例:

[code=C/C++]

A: //code section A

//code

goto B;

//code

goto C;

B: //code section B

//code

goto A;

//code

goto C;

C: //code section C

//code

//goto B;

//code

goto A;

[/code]

這樣好像已經能夠說明問題了,隨著標籤的增多,帶來的混亂局面是很難扭轉的,對調試,走讀,理解代碼都會造成很大的障礙,如果你寫這樣的代碼,那代碼維護絕對會是一場 噩夢。

2). 不加限制地使用goto經常帶來錯誤或隱患。它可能跳過了某些對象的構造、變數的初始化、重要的計算等語句,例如:

goto state;

String s1, s2; // 被goto 跳過

int sum = 0; // 被goto 跳過

…..

……

state:

……

如果編譯器不能發覺此類錯誤,每用一次goto 語句都可能留下隱患。

四.Goto語句與結構化程式設計

goto語句問題的提出直接推動了結構化程式設計(structured programming)的思想和程式設計方法學的誕生和發展。結構化程式設計方法引入了工程思想和結構化思想,使大型軟體的開發和編程都得到了極大的改善。

結構化程式設計方法的主要原則可以概括為自頂向下,逐步求精,模組化,限制使用goto語句。

1.自頂向下:程式設計時,應先考慮總體,後考慮細節;先考慮全局目標,後考慮局部目標。不要一開始就過多追求眾多的細節,先從最上層總目標開始設計,逐步使問題具體化。

2.逐步求精:對複雜問題,應設計一些子目標作為過渡,逐步細化。

3.模組化:一個複雜問題,肯定是由若干稍簡單的問題構成。模組化是把程式要解決的總目標分解為子目標,再進一步分解為具體的小目標,把每一個小目標稱為一個模組。

4.限制使用goto語句

結構化程式設計方法的起源來自對goto語句的認識和爭論。肯定的結論是,在塊和進程的非正常出口處往往需要用goto語句,使用goto語句會使程式執行效率較高;在合成程式目標時,goto語句往往是有用的,如返回語句用goto。否定的結論是,goto語句是有害的,是造成程式混亂的禍根,程式的質量與goto語句的數量呈反比,應該在所有高級程式設計語言中取消goto語句。取消goto語句後,程式易於理解、易於排錯、容易維護,容易進行正確性證明。作為爭論的結論,1974年Knuth發表了令人信服的總結,並證實了:

(1)goto語句確實有害,應當儘量避免;

(2)完全避免使用goto語句也並非是個明智的方法,有些地方使用goto語句,會使程式流程更清楚、效率更高。

(3)爭論的焦點不應該放在是否取消goto語句上,而應該放在用什麼樣的程式結構上。其中最關鍵的是,應在以提高程式清晰性為目標的結構化方法中限制使用goto語句

五.關於goto使用語句的一些建議

goto語句在結構化編程技術出來後,被當作破壞結構化程式的典型代表,可以說,在結構化程式設計年代,goto語句就像洪水猛獸一樣,程式設計師都唯恐避之不及;可後來在微軟的一些例子程式中經常把goto語句用來處理出錯,當出錯時,goto到函式要退出的一個label那裡進行資源釋放等操作。那么,goto語句是不是只可以用於出錯處理,其他地方都不可以用了呢?下列關於使用goto語句的原則可以供讀者參考。

1) 使用goto語句只能goto到同一函式內,而不能從一個函數裡goto到另外一個函數裡。

2) 使用goto語句在同一函式內進行goto時,goto的起點應是函式內一段小功能的結束處,goto的目的label處應是函式內另外一段小功能的開始處。

3) 不能從一段複雜的執行狀態中的位置goto到另外一個位置,比如,從多重嵌套的循環判斷中跳出去就是不允許的。

4)應該避免向兩個方向跳轉。這樣最容易導致"麵條代碼"。

相關詞條

相關搜尋

熱門詞條

聯絡我們