死循環(無法靠自身的控制終止的循環)

死循環(無法靠自身的控制終止的循環)

本詞條是多義詞,共2個義項
更多義項 ▼ 收起列表 ▲

在編程中,一個靠自身控制無法終止的程式稱為“死循環”。

基本介紹

  • 中文名:死循環
  • 外文名:endless loop
  • 定義:靠自身控制無法終止的程式
  • 類型:編程
編程-死循環,頁面-死循環,舉例,邏輯錯誤,變數處理錯誤,奧爾德森循環,無窮遞歸,多個模組產生的死循環,假死循環,

編程-死循環

例如在C語言程式中,語句“while(1)printf("*");”就是一個死循環,運行它將無休止地列印*號。
不存在一種算法,對任何一個程式及相應的輸入數據,都可以判斷是否會出現死循環。因此,任何編譯系統都不做死循環檢查。
在設計程式時,若遇到死循環,我們可以通過按下Ctrl+Pause/Break的方法,結束死循環。
然而,在編程中死循環並不是一個需要避免的問題,相反,在實際套用中,經常需要用到死循環。例如,我們使用的Windows作業系統下的視窗程式中的視窗都是通過一個叫訊息循環的死循環實現的。在單片機、嵌入式編程中也經常要用到死循環。在各類程式語言中,死循環都有多種實現的方法,以C語言為例,可分別使用while.for,goto實現。
死循環的C語言實現:
1、while(1);
2、for(;;);
3、goto
Loop:
...
goto Loop;

頁面-死循環

在網站頁面設計當中,導航的設計不可忽視。導航的作用除了給用戶尋找相關信息文字性的提示以外。也是增加此頁面連結其他頁面的入口。如果此頁面的導航點擊進入時連結地址還是本頁面,就會造成死循環。頁面死循環不利於網站以及網頁的最佳化。
死循環在系統的套用非常多,也非常重要,所有的套用系統都需要設定一個死循環來保證系統的正常運行,如果沒有死循環,那么你會一開機馬上就關機,因為這個程式已經運行完畢,所以在系統開發中死循環有著極其重要的作用!

舉例

以下是一些死循環的例子。
C++的例子
#include<iostream>int main(){    for(int i=0;;i++)    {        cout<<char(i);    }    return 0;}
C語言的死循環:
#include <stdio.h>main(){    int a = 0;    while (a < 10)    {        printf("%d\n", a);        if (a = 5) {            printf("a equals 5!\n");        }        a++;    }    return 0;}
上述程式會一直顯示"Infinite Loop"字元串。
BASIC語言的死循環:
10 PRINT"Infinite Loop"
20 GOTO10'跳到行號=10的位置
X86彙編語言的例子:
loop:
; Code to loop here
jmploop
Python的例子:
whileTrue:
print("Infinite Loop")

邏輯錯誤

以下是一個Visual Basic死循環的例子:
dimxasintegerdountilx > 5'根本不會有x>5的情形x = 1 x = x + 1loop
每一次運行循環時x會先設定為1,然後變為2,因為數值未大於5,所以永遠不會退出。若將x = 1由循環內部移到循環之前即可以改善此一情形。
有些程式設計師可能因為不熟悉特定程式語言的語法而造成死循環,例如以下是一段C語言的程式:
#include <stdio.h>main(){    int a=0;    while(a<10)    {        printf("%d\n",a);        if(a=5){ printf("a equals 5!\n"); //a設定為5,進入無窮迴圈}
        a++;    }    return 0;}
其預期輸出是數字0至9,其中5和6中間會顯示"a equals 5!",但程式設計師在編寫程式時將設定用的=運算符及判斷相同的==運算符弄混了,因此程式會在每次運行循環時都會將a設定為5,因此變數a永遠無法到達10,此循環就變成了死循環。

變數處理錯誤

有時不適當的循環退出條件也可能會造成無預期的死循環,例如以下C語言的例子:
float x=0.1;while(x!=1.1){    //可能會因為浮點運算的誤差而出現問題    printf("x = %f\n",x);    x=x+0.1;}
在有些作業系統中,上述程式會運行10次循環然後退出,但有些系統中,上述程式卻可能會一直運行,無法退出,問題主要在循環的退出條件(x != 1.1)要在二個浮點數相等時才退出,結果會依系統處理浮點數的方式而定,只要系統運行10次循環後的結果和1.1差一點點,上述程式就會變成死循環。
若將退出條件改為(x < 1.1)就沒有這個問題,程式可能會多運行一次循環,但不會變成死循環。另一種解決方式則是用一個整數變數作為循環變數,再依此變數判斷是否要退出循環。
數值分析程式中也可能會出現無預期的死循環,例如程式需一直疊代到誤差小於某特定值為止,但若因為運算中的捨去誤差,使得誤差一直無法小於該特定值,就會產生死循環。

奧爾德森循環

奧爾德森循環(Alderson loop)是指一個循環有設定退出條件,但因為程式的寫法(多半是編程錯誤),造成永遠無法滿足退出條件,在針對用戶界面程式調試時最容易出現這類的問題。
以下C的偽代碼中有一個奧爾德森循環,程式是要計算用戶輸入一串數字的和,用戶輸入0時退出循環,但程式中用了不正確的運算符:
sum=0;while(true){printf("Input a number to add to the sum or 0 to quit");i=getUserInput();if(i*0){// 若i乘0為真,則使sum加上i的值sum+=i;// 但這不可能發生,因為不論i為何值(i * 0)都是0。如果條件中用的是!=而非*,代碼就能正常運行}if(sum>100){break;// 終止循環。結束條件存在,但從來沒有達到過,因為sum永遠不會增加}}
“奧爾德森循環”是來自一個Microsoft Access的程式設計師,他編寫的程式產生一個有模式的對話框,用戶需要回應,程式才能繼續運作,但對話框沒有OK鍵或取消鍵,因此只要此對話窗出現,Access程式就無法繼續運作。

無窮遞歸

無窮遞歸是一種由遞歸造成的死循環。例如以下計算階乘的C語言程式
unsigned int fac(unsigned int a){    //n!=n*(n-1)!    return(fac(a-1)*a);}
一般遞歸的程式會有一特定條件,此條件成立時直接計算結果,而不是通過遞歸來計算結果,若程式中未定義此條件,就會出現無窮遞歸。
無窮遞歸會造成堆疊溢出,而無窮遞歸不會退出,因此也是死循環的一種。不過若遞歸程式是使用尾部遞歸的處理方式,在有些程式語言(如Scheme)中會最佳化成循環,因此不會造成堆疊溢出。
上述的程式可以修改成沒有無窮遞歸的程式。
unsigned int fac(unsigned int a){    if(a==0)    {    //定義0!=1        return 1;    }       else    {        return(fac(a-1)*a);    }}

多個模組產生的死循環

死循環也可能因為多個模組之間的互動而產生。考慮一台伺服器若收到無法理解的需求時,會回應錯誤信息,此架構中不會有死循環。但若有二台上述的伺服器(A和B),互相交換數據,A收到由B所提交無法理解的需求,會回應錯誤信息給B,但若B也無法理解A提交的需求(其實是A的錯誤信息),會再以自己的格式回應錯誤信息給,A收到後無法理解,會再回應錯誤信息給B……。像郵件循環就是這類的例子。

假死循環

假死循環是指一個循環看似不會退出,但只是一個運行很長時間,最後仍會退出的循環。
以下是一個C語言for循環的程式:
unsigned int i;
for(i=1;i!=0;i++)
{/* loop code */}
上述程式每次運行時都將i加1,若i等於0時才會退出循環,此程式看似不會退出,但最後還是會退出。程式中型態為unsigned int的變數,其數值有一定上限,當數值已到上限,再加1時,變數數值就會變為0,因此讓程式退出。實際的上限值依系統及編譯器而不同,假如unsigned int是一個16個比特的字元組,上述的循環會運行65536次。若使用高精度計算,程式會一直運行到存儲器無法存儲i為止。

相關詞條

熱門詞條

聯絡我們