複製鏈接
請複製以下鏈接發送給好友

死循環

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

鎖定
死循環(endless loop)是指無法靠自身的控制終止的循環,在編程中,一個靠自身控制無法終止的程序。
中文名
死循環
外文名
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>
intmain()
{
for(inti=0;;++i)
{
cout<<char(i);
}
return0;
}
C語言的死循環:
#include<stdio.h>
intmain()
{
inta=0;
while(a>=0)
{
printf("%d\n",a);
if(a==5){
printf("aequals5!\n");
}
a++;
}
return0;
}
上述程序會一直顯示"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循環的程序:
for(i=1;i!=0;i++)
{/* loop code */}
上述程序每次運行時都將i加1,若i等於0時才會退出循環,此程序看似不會退出,但最後還是會退出。程序中型態為unsigned int的變量,其數值有一定上限,當數值已到上限,再加1時,變量數值就會變為0,因此讓程序退出。實際的上限值依系統及編譯器而不同,假如unsigned int是一個16個比特的字符組,上述的循環會運行65536次。若使用高精度計算,程序會一直運行到存儲器無法存儲i為止。