程序設(shè)計和調(diào)試中的幾點總結(jié)。 在調(diào)試過程中 ,遇到了許多困難。
1. 不知道如何在函數(shù)中傳遞數(shù)組做實參,一開始連如何定義函數(shù)中的形參都不知道,還是用了幫助才了解,正式發(fā)現(xiàn)F1的幫助作的十分貼心,很好用,只是不太會用。我想,學好如何使用幫助能夠大大縮短學習的周期。
數(shù)組實參的傳遞最后解決了,要在type 中對數(shù)組進行定義 ,如下操作:
Type
arr1=array[1..100] of integer ;
這樣就定義了一個數(shù)組類型---arr1,以后聲明數(shù)組只要 x :arr1 ; 而不用 x :array[1..100] of integer ;在數(shù)組的實參傳遞中只要使用數(shù)組名,如下:
//函數(shù)定義
function f1( x,y :arr1 ) :real ;
begin
.....
end;
//函數(shù)使用
p := f1(x,y) ; //x,y 分別為兩個數(shù)組。
2. 在插值調(diào)試過程中,算法是以知的,具體的代碼調(diào)試要求比較細心。對于變量的定義尤其要注意,應當遵守一定的規(guī)則,否則在以后的維護和修改中會帶來許多不必要的麻煩,更有可能帶來許多意想不到的錯誤,這一點在以后說明。對于書上已經(jīng)寫好的算法,可能由于你取數(shù)組下標不同(0或1),循環(huán)變量起點不同而有所差異,不能照抄。有時錯誤往往在一個符號(如:>寫成< 等)。
3 . 對于delphi提供的函數(shù)、方法,他們在使用時都有一定的提示。比如 edit1. 當你.下去的時候就會列出此時可以使用的方法,如果沒有找到你要用的方法只有2種情況:①沒有該方法。②你在某地方有錯誤,使該方法不能顯現(xiàn)出來。比如:inttostr(edit1.Text) ,在寫好edit1. 后,找不到Text方法。因為用的函數(shù)錯誤,inttostr()中用的是整數(shù)值,但是 edit1.Text 是字符串類型,所以不會顯示。用這種方法可以自我檢測。
4. 對于變量的規(guī)范命名是十分必要和有用的,這在編寫一些小程序中察覺不出來。因為在小程序中使用不了許多變量,容易管理,用腦子就可以記住,不會產(chǎn)生許多麻煩。而在大程序中,尤其是多人合力完成的程序,你自己定義的變量別人也許不知道,所以規(guī)范的命名有助于別人和自己管理和維護程序。如果定義不得當?shù)脑挘锌赡艹霈F(xiàn)意想不到的錯誤。我在寫Unit1的代碼時就遇到了這樣的情況。在寫一次線性插值的時候,在處理邊緣點的時候出現(xiàn)了錯誤。
錯誤是這樣的:當輸入點后,第一次按插值按鈕,沒有錯誤。但是在按一次按鈕就出錯了,這是為什么呢?為什么其他的插值沒有出現(xiàn)類似問題呢?我進行了單步調(diào)試,發(fā)現(xiàn)了出錯的地方是循環(huán)變量出錯。當按第二次的時候,循環(huán)變量改變了,從而使結(jié)果出錯。一看循環(huán)變量,原來是i ,而我又用i做了全局變量,由于全局變量中儲存的是循環(huán)的次數(shù),因而就沒有在函數(shù)中定義i變量,而直接用全局變量代替局部變量。這樣局部的改變影響到全局,就是錯誤的根源。所以,通過這件事,我深刻的了解到規(guī)范命名和注釋的重要性。
5. 在對form進行退出過程的執(zhí)行是一定要注意,如果你對任何一個form進行了操作,如果對其有影響的話,那么就要在調(diào)用form的退出過程是進行復原操作,這是必須的工作,也是很重要的工作之一。
在對form的退出過程的編寫的時候要注意幾個方面:首先,如果你要關(guān)閉的form中有一些可視的
組件,如:edit,listbox,label,memo等等一些組件,那么就要將這些組件的內(nèi)容恢復form剛創(chuàng)建時的樣子,這是十分必須的一步工作。別小看了這一步工作,這有可能給你帶來捆饒。大多數(shù)我們調(diào)用form使用的語句是formx.show 。而該語句僅僅把你所要調(diào)用的form顯示出來而不做其他任何事情,更別說是初始化工作,所以我們要對該form在上次退出的時候就進行初始化工作,以便為我們本次的操作打好基礎(chǔ)。否則,上次操作留下的數(shù)據(jù)會繼續(xù)在form中顯示,從而影響我們本次的操作。
其次,在form的退出過程的編寫也要注意某些有漏洞的地方,初學者往往容易犯這樣的錯誤。比如:大家往往習慣與用form.close來關(guān)閉窗口,這是對的,有時我們會單獨做一個退出按鈕,里面調(diào)用了form.close,并且對本form進行了還原,這一切都很正常。但是在他使用form自帶的叉型圖標來關(guān)閉form時就會遇到麻煩。再次進入時會發(fā)現(xiàn)上次退出的時候沒有進行還原操作,但是還原操作的代碼明明寫了,這是為什么呢?因為form自帶的關(guān)閉只調(diào)用了form.close,而不進行其他操作,解決的方法就是在form的Onclose事件中加入還原代碼就可以了。而在自己添加的退出按鈕的過程代碼段中也只需要用一句show.close,還原的是就交給了OnClose Event來完成。
再者,在form關(guān)閉的時候,如果對其他的form有過改動,必須要還原,否則會出現(xiàn)上面講過的錯誤。有時兩個form互相影響,就要互相還原。這樣難免就要用到對方form的unit,用語句uses unitx ;而這也有規(guī)定。在interface 里,是不能互相uses 的。如果在interface 里互相uses,系統(tǒng)會報錯 Circle use ;所以只能夠一個在interface中,另一個在implementation 里uses,或者兩個都在implementation里uses。
6. 文件的共享,這是一個減少代碼量和減少重復勞動,減少代碼冗余的好方法。具體來說就是寫一個公共的unit,把多個form都要用到的函數(shù)、過程、數(shù)據(jù)、類型等等都放在一起,這樣便于管理和修改。在每個要用到該unit中的函數(shù)的unit中uses一下就可以了。不過有一點很重要,那就是要為每一個函數(shù),過程寫一個聲明,這樣的話別的unit才能夠看見這些函數(shù)和過程。否則,僅僅在implementation中寫了函數(shù)、過程的實現(xiàn)而不寫聲明的話,他們只在本unit可見,著一點很重要。切記,切記!
7. 對于命名規(guī)則我再多說一點,在給變量命名的時候要考慮到他的邏輯性。也就是說給這個變量起的名字是有意義的,能夠讓人一看見就能夠知道他是干什么用的。這樣不僅僅方便維護人員管理與維護,也方便自己理清思路,可以很快的判斷出邏輯表達試。在這方面,邏輯變量的體現(xiàn)最為明顯,比如: 定義一個邏輯變量 flag 這樣我們就可以看出 flag 是標記的意思。那么當有標記也就是 flag=true 時,我們可以寫成
if flag then ……
而不是寫成 if flag=true then …… 對于前一種寫法他的邏輯性更強,而且易于我們的邏輯思維。但是初學者往往會用后一種寫法,這是對 Boolean 類型不太熟悉造成的,我們要養(yǎng)成習慣。盡量使自己的程序的邏輯性強,而且遵守編程規(guī)范,這樣會給我們和他人節(jié)省很多寶貴的時間和精力。在給函數(shù)的形參和實參起名字的時候也要有意義,這樣才不至于搞混淆。我就遇到了這樣的情況,在該設(shè)計的 unit2 中,做的是有關(guān)積分的東西,積分分為上限和下限,這兩個限定一旦搞錯就會出現(xiàn)錯誤,如果是全部都搞錯還比較容易糾正,上限和下限顛倒過來只是值變成相反數(shù)。如果一部分搞錯,一部分是對的,那么就錯的有夠離譜了,這樣的錯誤往往不能從錯誤的結(jié)果加以判斷,只能分段查找程序中的問題。看是否在那里出錯,如此而已,費時費力,所以要進行合理的命名是十分重要的。
8. 調(diào)試工作中很重要的一步就是確定錯誤的位置,這個工作已經(jīng)由編譯器代替我們完成了。有時后編譯器完成的工作只是初步,具體的位置還是要求我們自己去找出來。有一些錯誤的定位由于某些原因會和實際出錯的位置差別比較大,這些位置的查找是要靠編程的經(jīng)驗和仔細的觀察才能夠找出來的,在實際中,良好的書寫習慣會幫助我們克服這些實際出錯位置和報錯位置差別比較大的錯誤。這些錯誤中,比較典型的就是:多寫或漏寫 begin 或 end ,使之沒有配對,從而造成程序的出錯。有時候?qū)?;,(),[ ] 的使用也會造成同樣的效果。克服這些錯誤就是要養(yǎng)成良好的書寫習慣,比如: 在寫程序的時候,一般在同一個循環(huán)內(nèi)的語句都要向左對齊,一個二重循環(huán)的內(nèi)循環(huán)要向內(nèi)縮進一些,用來區(qū)別與外循環(huán)。在寫 begin 和end 的時候就要一起寫,對于括號(),[ ] 也是一樣的處理,這樣一起寫的好處是以后不會漏掉另一個這樣我們在寫程序的時候就不需要記著前面我還在哪兒用了一個 begin,這里要寫一個 end 與之對應。這樣的好處在寫函數(shù)表達式的時候顯得尤其好用。在一個比較復雜的表達式中如果括號的層數(shù)超過3層就十分難以看清楚,這時良好的書寫習慣就會幫了你的大忙了。你不會為了找另一個對應的括號而瞅花了眼,只要一步一步的從里到外的寫出來,不會有太大困難。當然,別人要看懂是要花一定時間的,但是你寫的卻不會有錯。
除了定位錯誤之外還要改正錯誤,當然我前面講的方法大都是改正錯誤,但是最有效的就是看編譯器給你的提示信息。這是我們查找錯誤的出發(fā)點,其中的一些小錯誤很容易就能看出來,比如:變量沒有聲明,在 else 前加了 ; ,類型不對應,函數(shù)參數(shù)傳遞錯誤等。而有一些錯誤是從信息中看不出來的,語法的錯誤不太難糾正,但是算法的錯誤就不好糾正了。這就要求我們用調(diào)試工具來一步步找出錯誤。其中最常用到的工具就是斷點、單步進入、單步跳出,以及 觀察變量。斷點可以幫助我們將程序分段,看一看到底是在那一部分出了錯,以便于查找。不過在調(diào)試完畢以后一定要記著把斷點都清除掉,不然你的程序會在運行時突然中斷,而你也查不出錯。我個人比較愛用的是單步進入+單步跳出+Add Watch 這是調(diào)試程序的一個必由之路。寫程序并不難,調(diào)試程序的高手才是很有本事的人,我一向是這么認為。單步進入 就是一步一步的調(diào)試,邊解釋邊運行,這樣便于我們找到錯誤。單步跳出 是為了幫助單步進入的,單步跳出對于一個過程或者是一個函數(shù)是將其看成一條語句,一下子跳過去,這樣節(jié)省了那些正確的部分的檢查。也可以用 運行到光標處這一項,兩者都是縮短正確的程序段的檢查時間。 Add Watch 是一個非常好用的東東,你可以在里面加入你想要監(jiān)視的變量名稱。則該變量的值會在表中顯示出來,他配合單步操作,可以看見你想要知道的變量在每一步的變化情況是否和預料的一樣變化。如果有出入則可以對該語句進行分析,從而找出出錯的原因。可見單步操作+Add Watch 是調(diào)試程序必不可少的步驟,也是最有效的方法。但是,在程序比較復雜,調(diào)用函數(shù)比較多的時候,單步進入就不是那么好用了。因為往往在一個按鈕事件中有用到好幾個
PRocedure 或者 function ,在每一個function或者procedure中往往又要調(diào)用別的function和 procedure。所以用單步進入很容易讓人搞的暈頭轉(zhuǎn)向,不知所云。假如用到了第三方的控件,那就更不知道程序運行到什么地方了。所以,在程序量比較大,而且調(diào)用函數(shù)比較多的地方,單步操作就不太好用了。這時我們最好使用斷點工具,他使用的意義和單步操作的意義是一樣的,就是為了看清楚程序是否按我們所設(shè)計的思路在運行。斷點的好處就是在于他可以使我們在希望停止的地方暫停,而其余不需要停止的地方則按原來的速率進行運行。結(jié)合Add Watch,我們就可以看見整個程序運行的過程了。斷點的增加是比較有講究的,一般情況下都要在以下幾個地方加上斷點: ①循環(huán)語句的入口處,在此處加上斷點可以監(jiān)視進入循環(huán)的數(shù)據(jù),看看是否在循環(huán)以前就有錯誤。在每個循環(huán)前放一個就象作一個備份一樣,看看會出什么樣的結(jié)果。 ②在循環(huán)語句的最后一句設(shè)置一個斷點,這樣就可以監(jiān)視每一次的循環(huán)過程,看看是在那一次循環(huán)出錯。還有一個好處就是這樣在循環(huán)內(nèi)部設(shè)置一個斷點可以防止無限循環(huán)。萬一你編寫的程序出錯,出現(xiàn)了無限循環(huán),這樣會造成系統(tǒng)資源急劇下降,從而容易造成死機。如果你沒有備份這次所做的工作的話,那真是欲哭無淚了。 ③在循環(huán)完成處設(shè)置一個斷點,這樣可以把入口處和出口處進行對照,看一看該循環(huán)是否按照你的要求正常工作,可以很快的判斷出循環(huán)語句的正確性。 ④在判斷語句前設(shè)置斷點,這個斷點主要的目的是觀察此時的Add Watch 中的值。此時的各個判斷參數(shù)的值可以看出程序是否按照正常步驟進行,或者在判斷語句中出現(xiàn)了邏輯錯誤,這些都是很常見的斷點設(shè)置處。
9. 設(shè)置procedure 和function 的各種用法。不要小看了var 這三個字,我們通常在定義變量中使用,而他的一個很重要的用途就是在 procedure 或者function中設(shè)置變參。變參在普通的procedure 和function中不是很常用,但是卻有著十分重要的用途。如果你想編寫一個函數(shù),要返回兩個值,因為這兩個值是在同一個函數(shù)中得出的。所以想要有兩個返回值,但是函數(shù)只能有一個返回值,這時該如何解決呢?變參就派上了用場,在函數(shù)和過程中使用的變參會改變實參的值就象傳址函數(shù)一樣。這樣的話,在一個過程或者函數(shù)中定義多個變參就可以返回多個參數(shù)了。