程式設計和除錯中的幾點總結 (轉)

amyz發表於2007-11-07
程式設計和除錯中的幾點總結 (轉)[@more@] 

 設計和中的幾點總結。:namespace prefix = o ns = "urn:schemas--com::office" />

在除錯過程中 ,遇到了許多困難。

1. 不知道如何在中傳遞陣列做實參,一開始連如何定義函式中的形參都不知道,還是用了幫助才瞭解,正式發現F1的幫助作的十分貼心,很好用,只是不太會用。我想,學好如何使用幫助能夠大大縮短學習的週期。

  陣列實參的傳遞最後解決了,要在type 中對陣列進行定義 ,如下操作:

  Type

   arr1=array[1..100] of integer ;

  這樣就定義了一個陣列型別---arr1,以後宣告陣列只要 x :arr1 ; 而不用 x :array[1..100] of integer ;在陣列的實參傳遞中只要使用陣列名,如下:

  //函式定義

  function  f1( x,y :arr1 ) :real ;

  begin

  .....

  end;

  //函式使用

  p := f1(x,y) ;  //x,y 分別為兩個陣列。

2. 在插值除錯過程中,演算法是以知的,具體的程式碼除錯要求比較細心。對於變數的定義尤其要注意,應當遵守一定的規則,否則在以後的維護和修改中會帶來許多不必要的麻煩,更有可能帶來許多意想不到的錯誤,這一點在以後說明。對於書上已經寫好的演算法,可能由於你取陣列下標不同(0或1),迴圈變數起點不同而有所差異,不能照抄。有時錯誤往往在一個符號(如:>寫成< 等)。

3 . 對於提供的函式、方法,他們在使用時都有一定的提示。比如 edit1. 當你.下去的時候就會列出此時可以使用的方法,如果沒有找到你要用的方法只有2種情況:①沒有該方法。②你在某地方有錯誤,使該方法不能顯現出來。比如:inttostr(edit1.Text) ,在寫好edit1. 後,找不到Text方法。因為用的函式錯誤,inttostr()中用的是整數值,但是 edit1.Text 是字串型別,所以不會顯示。用這種方法可以自我檢測。

4. 對於變數的規範命名是十分必要和有用的,這在編寫一些小程式中察覺不出來。因為在小程式中使用不了許多變數,容易管理,用腦子就可以記住,不會產生許多麻煩。而在大程式中,尤其是多人合力完成的程式,你自己定義的變數別人也許不知道,所以規範的命名有助於別人和自己管理和維護程式。如果定義不得當的話,有可能出現意想不到的錯誤。我在寫Unit1的程式碼時就遇到了這樣的情況。在寫一次線性插值的時候,在處理邊緣點的時候出現了錯誤。

錯誤是這樣的:當輸入點後,第一次按插值按鈕,沒有錯誤。但是在按一次按鈕就出錯了,這是為什麼呢?為什麼其他的插值沒有出現類似問題呢?我進行了單步除錯,發現了出錯的地方是迴圈變數出錯。當按第二次的時候,迴圈變數改變了,從而使結果出錯。一看迴圈變數,原來是i ,而我又用i做了全域性變數,由於全域性變數中儲存的是迴圈的次數,因而就沒有在函式中定義i變數,而直接用全域性變數代替區域性變數。這樣區域性的改變影響到全域性,就是錯誤的根源。所以,透過這件事,我深刻的瞭解到規範命名和註釋的重要性。

5. 在對form進行退出過程的是一定要注意,如果你對任何一個form進行了操作,如果對其有影響的話,那麼就要在form的退出過程是進行復原操作,這是必須的工作,也是很重要的工作之一。

  在對form的退出過程的編寫的時候要注意幾個方面:首先,如果你要關閉的form中有一些可視的,如:edit,listbox,label,memo等等一些元件,那麼就要將這些元件的內容恢復form剛建立時的樣子,這是十分必須的一步工作。別小看了這一步工作,這有可能給你帶來捆饒。大多數我們呼叫form使用的語句是formx.show 。而該語句僅僅把你所要呼叫的form顯示出來而不做其他任何事情,更別說是初始化工作,所以我們要對該form在上次退出的時候就進行初始化工作,以便為我們本次的操作打好基礎。否則,上次操作留下的資料會繼續在form中顯示,從而影響我們本次的操作。

  其次,在form的退出過程的編寫也要注意某些有的地方,初學者往往容易犯這樣的錯誤。比如:大家往往習慣與用form.close來關閉視窗,這是對的,有時我們會單獨做一個退出按鈕,裡面呼叫了form.close,並且對本form進行了還原,這一切都很正常。但是在他使用form自帶的叉型圖示來關閉form時就會遇到麻煩。再次進入時會發現上次退出的時候沒有進行還原操作,但是還原操作的程式碼明明寫了,這是為什麼呢?因為form自帶的關閉只呼叫了form.close,而不進行其他操作,解決的方法就是在form的Onclose事件中加入還原始碼就可以了。而在自己新增的退出按鈕的過程程式碼段中也只需要用一句show.close,還原的是就交給了OnClose Event來完成。

再者,在form關閉的時候,如果對其他的form有過改動,必須要還原,否則會出現上面講過的錯誤。有時兩個form互相影響,就要互相還原。這樣難免就要用到對方form的unit,用語句uses unitx ;而這也有規定。在interface 裡,是不能互相uses 的。如果在interface 裡互相uses,會報錯 Circle use ;所以只能夠一個在interface中,另一個在implementation 裡uses,或者兩個都在implementation裡uses。

6. 的共享,這是一個減少程式碼量和減少重複勞動,減少程式碼冗餘的好方法。具體來說就是寫一個公共的unit,把多個form都要用到的函式、過程、資料、型別等等都放在一起,這樣便於管理和修改。在每個要用到該unit中的函式的unit中uses一下就可以了。不過有一點很重要,那就是要為每一個函式,過程寫一個宣告,這樣的話別的unit才能夠看見這些函式和過程。否則,僅僅在implementation中寫了函式、過程的實現而不寫宣告的話,他們只在本unit可見,著一點很重要。切記,切記!

7.  對於命名規則我再多說一點,在給變數命名的時候要考慮到他的邏輯性。也就是說給這個變數起的名字是有意義的,能夠讓人一看見就能夠知道他是幹什麼用的。這樣不僅僅方便維護人員管理與維護,也方便自己理清思路,可以很快的判斷出邏輯表達試。在這方面,邏輯變數的體現最為明顯,比如: 定義一個邏輯變數 flag 這樣我們就可以看出 flag 是標記的意思。那麼當有標記也就是 flag=true 時,我們可以寫成

if  flag   then ……

而不是寫成  if  flag=true  then …… 對於前一種寫法他的邏輯性更強,而且易於我們的邏輯思維。但是初學者往往會用後一種寫法,這是對 Boolean 型別不太熟悉造成的,我們要養成習慣。儘量使自己的程式的邏輯性強,而且遵守規範,這樣會給我們和他人節省很多寶貴的時間和精力。在給函式的形參和實參起名字的時候也要有意義,這樣才不至於搞混淆。我就遇到了這樣的情況,在該設計的 unit2 中,做的是有關積分的東西,積分分為上限和下限,這兩個限定一旦搞錯就會出現錯誤,如果是全部都搞錯還比較容易糾正,上限和下限顛倒過來只是值變成相反數。如果一部分搞錯,一部分是對的,那麼就錯的有夠離譜了,這樣的錯誤往往不能從錯誤的結果加以判斷,只能分段查詢程式中的問題。看是否在那裡出錯,如此而已,費時費力,所以要進行合理的命名是十分重要的。

8. 除錯工作中很重要的一步就是確定錯誤的位置,這個工作已經由代替我們完成了。有時後編譯器完成的工作只是初步,具體的位置還是要求我們自己去找出來。有一些錯誤的定位由於某些原因會和實際出錯的位置差別比較大,這些位置的查詢是要靠程式設計的和仔細的觀察才能夠找出來的,在實際中,良好的書寫習慣會幫助我們克服這些實際出錯位置和報錯位置差別比較大的錯誤。這些錯誤中,比較典型的就是:多寫或漏寫 begin 或 end ,使之沒有配對,從而造成程式的出錯。有時候對 ;,(),[ ] 的使用也會造成同樣的效果。克服這些錯誤就是要養成良好的書寫習慣,比如: 在寫程式的時候,一般在同一個迴圈內的語句都要向左對齊,一個二重迴圈的內迴圈要向內縮排一些,用來區別與外迴圈。在寫 begin 和end 的時候就要一起寫,對於括號(),[ ] 也是一樣的處理,這樣一起寫的好處是以後不會漏掉另一個這樣我們在寫程式的時候就不需要記著前面我還在哪兒用了一個 begin,這裡要寫一個 end 與之對應。這樣的好處在寫函式的時候顯得尤其好用。在一個比較複雜的表示式中如果括號的層數超過3層就十分難以看清楚,這時良好的書寫習慣就會幫了你的大忙了。你不會為了找另一個對應的括號而瞅花了眼,只要一步一步的從裡到外的寫出來,不會有太大困難。當然,別人要看懂是要花一定時間的,但是你寫的卻不會有錯。

除了定位錯誤之外還要改正錯誤,當然我前面講的方法大都是改正錯誤,但是最有效的就是看編譯器給你的提示資訊。這是我們查詢錯誤的出發點,其中的一些小錯誤很容易就能看出來,比如:變數沒有宣告,在 else 前加了 ; ,型別不對應,函式引數傳遞錯誤等。而有一些錯誤是從資訊中看不出來的,語法的錯誤不太難糾正,但是演算法的錯誤就不好糾正了。這就要求我們用除錯工具來一步步找出錯誤。其中最常用到的工具就是斷點、單步進入、單步跳出,以及 觀察變數。斷點可以幫助我們將程式分段,看一看到底是在那一部分出了錯,以便於查詢。不過在除錯完畢以後一定要記著把斷點都清除掉,不然你的程式會在執行時突然中斷,而你也查不出錯。我個人比較愛用的是單步進入+單步跳出+Add Watch 這是除錯程式的一個必由之路。寫程式並不難,除錯程式的高手才是很有本事的人,我一向是這麼認為。單步進入 就是一步一步的除錯,邊解釋邊執行,這樣便於我們找到錯誤。單步跳出 是為了幫助單步進入的,單步跳出對於一個過程或者是一個函式是將其看成一條語句,一下子跳過去,這樣節省了那些正確的部分的檢查。也可以用 執行到游標處這一項,兩者都是縮短正確的程式段的檢查時間。 Add Watch 是一個非常好用的東東,你可以在裡面加入你想要監視的變數名稱。則該變數的值會在表中顯示出來,他配合單步操作,可以看見你想要知道的變數在每一步的變化情況是否和預料的一樣變化。如果有出入則可以對該語句進行分析,從而找出出錯的原因。可見單步操作+Add Watch 是除錯程式必不可少的步驟,也是最有效的方法。但是,在程式比較複雜,呼叫函式比較多的時候,單步進入就不是那麼好用了。因為往往在一個按鈕事件中有用到好幾個procedure 或者 function ,在每一個function或者procedure中往往又要呼叫別的function和 procedure。所以用單步進入很容易讓人搞的暈頭轉向,不知所云。假如用到了第三方的,那就更不知道程式執行到什麼地方了。所以,在程式量比較大,而且呼叫函式比較多的地方,單步操作就不太好用了。這時我們最好使用斷點工具,他使用的意義和單步操作的意義是一樣的,就是為了看清楚程式是否按我們所設計的思路在執行。斷點的好處就是在於他可以使我們在希望停止的地方暫停,而其餘不需要停止的地方則按原來的速率進行執行。結合Add Watch,我們就可以看見整個程式執行的過程了。斷點的增加是比較有講究的,一般情況下都要在以下幾個地方加上斷點: ①迴圈語句的入口處,在此處加上斷點可以監視進入迴圈的資料,看看是否在迴圈以前就有錯誤。在每個迴圈前放一個就象作一個一樣,看看會出什麼樣的結果。 ②在迴圈語句的最後一句設定一個斷點,這樣就可以監視每一次的迴圈過程,看看是在那一次迴圈出錯。還有一個好處就是這樣在迴圈內部設定一個斷點可以防止無限迴圈。萬一你編寫的程式出錯,出現了無限迴圈,這樣會造成系統資源急劇下降,從而容易造成當機。如果你沒有備份這次所做的工作的話,那真是欲哭無淚了。 ③在迴圈完成處設定一個斷點,這樣可以把入口處和出口處進行對照,看一看該迴圈是否按照你的要求正常工作,可以很快的判斷出迴圈語句的正確性。 ④在判斷語句前設定斷點,這個斷點主要的目的是觀察此時的Add Watch 中的值。此時的各個判斷引數的值可以看出程式是否按照正常步驟進行,或者在判斷語句中出現了邏輯錯誤,這些都是很常見的斷點設定處。

9. 設定procedure 和function 的各種用法。不要小看了var 這三個字,我們通常在定義變數中使用,而他的一個很重要的用途就是在 procedure 或者function中設定變參。變參在普通的procedure 和function中不是很常用,但是卻有著十分重要的用途。如果你想編寫一個函式,要返回兩個值,因為這兩個值是在同一個函式中得出的。所以想要有兩個返回值,但是函式只能有一個返回值,這時該如何解決呢?變參就派上了用場,在函式和過程中使用的變參會改變實參的值就象傳址函式一樣。這樣的話,在一個過程或者函式中定義多個變參就可以返回多個引數了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-981203/,如需轉載,請註明出處,否則將追究法律責任。

相關文章