Delphi 之 第八課 動態陣列

2022-07-29 09:06:10 字數 3264 閱讀 4353

delphi 4 的動態陣列

傳統的pascal 語言其陣列大小是預先確定的,當你用陣列結構宣告資料型別時,你必須指定陣列元素的個數。專業程式設計師也許知道些許動態陣列的實現技術,一般是採用指標,用手工分配並釋放所需的記憶體。

delphi 4中增加了非常簡單的動態陣列實現方法,實現過程效仿我前面講過的動態長字串。與長字串一樣,動態陣列的記憶體動態分配並且引用記數,不過動態陣列不支援 copy-on-write 技術。這不是個大問題,因為你可以把變數值設定為nil釋放陣列記憶體。

這樣你就可以宣告乙個不指定元素個數的陣列,並用setlength 過程給陣列分配乙個特定大小的記憶體,setlength 過程還可以改變陣列大小而不影響其內容,除此外還有一些字串過程也可用於陣列,如copy 函式。

以下摘錄的**突出了一點,這就是:定義陣列後必須先為它分配記憶體,然後才能開始使用:

proceduretform1.button1click(sender: tobject);vararray1:array ofinteger;beginarray1 [1] := 100; // error

setlength (array1, 100);

array1 [99] := 100; // ok

...end;

如果你只定義乙個陣列元素個數,那麼索引總是從0開始。pascal 中的普通陣列既能用不為零的下標,也能用非整數的下標,但動態陣列均不支援這兩種下標。象普通陣列一樣,你可以通過length、high和low 函式了解到動態陣列的狀況,不過對於動態陣列,low 函式返回值總是0,high函式返回陣列大小減1,這意味著空的動態陣列其函式high返回值是-1,這是乙個很怪的值,因為它比low的返回值還小。

圖 8.1: 例 dynarr 窗體

以上作了簡短的介紹,現在舉個簡例,例名dynarr ,見圖8.1。例子實在是很簡單,其實動態陣列沒有什麼特別複雜地方。我想通過該例說明幾個程式設計師可能犯的錯誤。程式中宣告了兩個全程陣列並在oncreate 事件中初始化了第乙個陣列:

vararray1, array2:array ofinteger;proceduretform1.formcreate(sender: tobject);begin// allocate

setlength (array1, 100);end;

這樣就把陣列所有值設定為0。完成這段**你馬上就能讀寫陣列元素的值,而不用害怕記憶體出錯,當然條件是你沒有試圖訪問超過陣列上界的元素。為了更好地初始化,程式中新增了乙個按鈕,執行陣列元素賦值操作:

proceduretform1.btnfillclick(sender: tobject);vari: integer;beginfori := low (array1)tohigh (array1)doarray1 [i] := i;end;
grow 按鈕用於修改陣列大小,但並不影響陣列內容。單擊grow 按鈕後,你可以用get value按鈕進行檢驗:

proceduretform1.btngrowclick(sender: tobject);begin// grow keeping existing values

setlength (array1, 200);end;proceduretform1.btngetclick(sender: tobject);begin// extract

caption := inttostr (array1 [99]);end;

alias 按鈕的onclick 事件**稍複雜些,程式通過 := 運算元把乙個陣列拷貝給另乙個陣列,從而有效地建立了乙個別名(乙個新變數,但引用記憶體中同一陣列)。從中可見,如果你改變了其中乙個陣列,那麼另乙個同樣也會改變,因為它們指向同乙個記憶體區:

proceduretform1.btnaliasclick(sender: tobject);begin// alias

array2 := array1;

// change one (both change)

array2 [99] := 1000;

// show the other

caption := inttostr (array1 [99]);

在btnaliasclick 事件中增加了兩部分操作內容。第一部分是陣列等同測試,不過並不是測試實際的陣列元素,而是測試陣列所引用的記憶體區,檢測變數是不是記憶體中同一陣列的兩個別名:

proceduretform1.btnaliasclick(sender: tobject);begin...ifarray1 = array2thenbeep;

// truncate first array

array1 := copy (array2, 0, 10);end;

btnaliasclick 事件的第二部分內容是呼叫copy 函式。該函式不僅把資料從乙個陣列移到另乙個陣列,而且用函式建立的新陣列取代第乙個陣列,結果變數array1 所引用的是11個元素的陣列,因此,按get value 和set value 按鈕將產生乙個記憶體錯誤,並且觸發乙個異常(除非你把範圍檢查range-checking 選項關掉,這種情況下,錯誤仍在但螢幕上不會顯示異常)。雖然如此,fill 按鈕仍能正常工作,因為需要修改的陣列元素由陣列當前的下標範圍確定。

結束語這一章內容暫時只包括動態陣列,動態陣列的確是記憶體管理的重要組成部分,但僅僅是其中的一部分,其它內容以後會逐步新增。

本章描述的記憶體結構屬於典型的 windows 程式設計內容,這方面內容將在下一章進行討論。

第八課 陣列

1 宣告 int arr string str 2 分配空間 arr new int 5 3 宣告同時分配記憶體 int arr new int 5 4 初始化 int arr new int 5 int arr2 1 宣告 int arr string str 2 分配空間 1 直接為每一維分配空...

第八課 混合

第八課 混合 opengl中的混色 在opengl中實現混色的步驟類似於我們以前提到的opengl過程。接著設定公式,並在繪製透明物件時關閉寫深度快取。因為我們想在半透明的圖形背後繪製 物件。這不是正確的混色方法,但絕大多數時候這種做法在簡單的專案中都工作的很好。rui martins 的補充 正確...

第八課 函式

1.id 標識 2.type 型別 3.value 值 關於可變物件的修改,可以參考下面程式理解 a 1,2,3 首先給a賦值列表,1,2,3 print a,id a 列印a,和a的id a 0 6 換掉列表a的第乙個值,改為6 print a,id a 列印a,和a的id,a的id和之前的一樣。...