程式調試主要有兩種方法,即靜態調試和動態調試。
程式的靜態調試就是在程式編寫完以後,由人工“代替”“類比”電腦,對程式進行
仔細檢查,主要檢查程式中的文法規則和邏輯結構的正確性。實踐表明,有很大一部分
錯誤可以通過靜態檢查來發現。通過靜態調試,可以大大縮短上機調試的時間,提高上機
的效率。程式的動態調試就是實際上機調試,它貫穿在編譯、串連和啟動並執行整個過程中。
根據程式編譯、串連和運行時電腦給出的錯誤資訊進行程式調試,這是程式調試中最
常用的方法,也是最初步的動態調試。在此基礎上,通過“分段隔離”、“設定斷點”、
“跟蹤列印”進行程式的調試。實踐表明,對於尋找某些類型的錯誤來說,靜態調試比
動態調試更有效,對於其他類型的錯誤來說剛好相反。因此靜態調試和動態調試是互相
補充、相輔相成的,缺少其中任何一種方法都會使尋找錯誤的效率降低。
靜態調試法
對程式文法規則進行檢查
(1)語句正確性檢查。保證程式中每個語句的正確性是編寫程式時的基本要求。
由於程式中包含大量的語句,書寫過程中由於疏忽或筆誤,語句寫錯再所難免。
對程式語句的檢查應注意以下幾點:
1.檢查每個語句的書寫是否有字元遺漏,包括必要的空格符是否都有。
2.檢查形體相近的字元是否書寫正確.例如字母o和數字0,書寫時要有明顯的分別。
3.檢查函數調用時形參和實參的類型、個數是否相同。
(2) 文法正確性檢查。每種電腦語言都有自己的文法規則,書寫程式時必須遵守一定的
文法規則,否則編譯時間程式將給出錯誤資訊。
語句的配對檢查:許多語句都是配對出現的,不能唯寫半個語句。另外,語句有多重括弧時,
每個括弧也都應成對出現,不能缺左少右的。
注意檢查語句順序:有些語句不僅句法本身要正確,而且語句在程式中的位置也必須正確。
例如,變數定義要放在所有可執行語句之前。
檢查程式的邏輯結構
(1) 檢查程式中各變數的初值和初值的位置是否正確。我們經常遇到的是“累加”、
“累乘”,其初值和位置都非常重要。用於累加的變數應取0初值或給定的初值,用於
累乘的變數應賦初值為或給定的值。因為累加或累乘都是通過迴圈結構來實現的,因此
這些變數賦初值語句應在迴圈體之外。對於多重迴圈結構,內迴圈體中的變數賦初值
語句應在內迴圈之外;外迴圈體中的變數賦初值語句應在外迴圈之外。如果賦初值的
位置放錯了,那麼將得不到預想的結果。
(2) 檢查程式中分枝結構是否正確。程式中的分枝結構都是根據給定的條件來決定執行
不同的路徑的,因此在設定各條路徑的條件時一定要謹慎,在設定“大於”、“小於”
這些條件時,一定要仔細考慮是否應該包括“等於”這個條件,更不能把條件寫反。
尤其要注意的是,實型資料在運算過程中會產生誤差,如果用“等於”或“不等於”對
實數的運算結果進行比較,則會因為誤差而產生誤判斷,直接選取也就錯了。因此在遇到
要判斷實數a與b相等與否作為條件來選擇路徑時,應該把條件寫成:if(fabs(a-b)<=1e-6),
而不應該寫成if (a==b)。要特別注意條件陳述式嵌套時,if和else的配對關係。
(3) 檢查程式中迴圈結構的迴圈次數和迴圈嵌套的正確性。C語言中可用for迴圈、while
迴圈、do—while迴圈。在給定迴圈條件時,不僅要考慮迴圈變數的初始條件,還要考慮
迴圈變數的變化規律、迴圈變數變化的時間,任何一條變化都會引起迴圈次數的變化。
(4) 檢查運算式的合理與否。程式中不僅要保證運算式的正確性,而且還要保證運算式
的合理性。尤其要注意運算式運算中的溢出問題,運算數值可能超出整數範圍就不應該
採用整型運算,否則必然導致運算結果的錯誤。兩個相近的數不能相減,以免產生
“下溢”。更要避免在一個分式的分母運算中發生“下溢”,因為編譯系統常把下溢
做零處理。因此分母中出現下溢時要產生“被零除”的錯誤。由於運算式不合理而引起
的程式運行錯誤往往很難尋找,會增加程式調試的難度。因此,認真檢查運算式的合理性,
是減少程式運行錯誤,提高程式動態調試效率的重要方面。
程式的靜態調試是程式調試非常重要的一步。初學者應培養自己靜態檢查的良好習慣,
在上機前認真做好程式的靜態檢查工作,從而節省上機時間,使有限的機時充分發揮作用。
動態調試法
在靜態調試中可以發現和改正很多錯誤,但由於靜態調試的特點,有一些比較隱形錯誤還不能檢查出來。只有上機進行動態調試,才能夠找到這些錯誤並改正它們。
編譯過程中的調試
編譯過程除了將來源程式翻譯成目標程式外,還要對來源程式進行語法檢查。如果發現來源程式有語法錯誤,系統將顯示錯誤資訊。使用者可以根據這些提示資訊尋找出錯誤性質,並在程式中出錯之處進行相應的修改。有時我們會發現編譯時間有幾行的錯誤資訊都是一樣的,檢查這些行本身沒有發現錯誤,這時要仔細檢查與這些行有關的名字、運算式是否有問題。例如,因為程式中數組說明語句有錯,這時,那些與該數組有關的程式行都會被編譯系統檢查出錯。這種情況下,使用者只要仔細分析一下,修改了數組說明語句的錯誤,許多錯誤就會同時沒有了。對於編譯階段的調試,要充分利用螢幕給出的錯誤資訊,對它們進行仔細分析判斷。只要注意總結經驗,使程式通過編譯是不難做到的。
串連過程的調試
編譯通過後要進行串連。串連的過程也有查錯的功能,它將指出外部調用、函數之間的聯絡及儲存區設定等方面的錯誤。如果串連時有這類錯誤,編譯系統也會給出錯誤資訊,使用者要對這些資訊仔細判斷,從而找出程式中的問題並改正之。串連時較常見的錯誤有以下幾類:
(1) 某個外部調用有錯,通常系統明確提示了外部調用的名字,只要仔細檢查各模組中與該名有關的語句,就不難發現錯誤。
(2) 找不到某個庫函數或某個庫檔案,這類錯誤是由於庫函數名寫錯、疏忽了某個庫檔案的串連等。
(3) 某些模組的參數超過系統的限制。如,模組的大小、庫檔案檔案的個數超出要求等。
引起串連錯誤的原因很多,而且很隱蔽,給出的錯誤資訊也不如編譯時間給出的直接、具體。因此,串連時的錯誤要比編譯錯誤更難尋找,需要仔細分析判斷,而且對系統的限制和要求要有所瞭解。
運行過程中的調試
運行過程中的調試是動態調試的最後一個階段。這一階段的錯誤大體可分為兩類:
(1) 運行程式時給出出錯資訊。
運行時出錯多與資料的輸入、輸出格式有關,與檔案的操作有關。如果給出資料格式有錯,這時要為要有關的輸入輸出資料格式進行檢查,一般容易發現錯誤。如果程式中的輸入輸出函數較多,則可以在中間插入調試語句,採取分段隔離的方法,很快就可以確定錯誤的位置了。如果是檔案操作有誤,也可以針對程式中的有關檔案的操作採取類似的方法進行檢查。
(2) 運行結果不正常或不正確。