技術交流,DH講解.
首先我們要知道什麼是數組?數組是一堆相同特性資料的一個集合,也就是每個元素的類型必須是一樣的,當然在其他一些弱文法的語言裡面,數組的元素可以千奇百怪.
例子:
Var A: Array[ 0..2 ] Of Integer ;Begin A[ 0 ] := 1 ; A[ 1 ] := 1.0 ; //這裡是錯的,因為每個元素都必須是Integer類型End ;
Delphi中數組分類:
1 定長和不定長.
定長數組:也就是長度在聲明的時候就確定了,後面是不能改變的,而在定長數組中,起始序號不必從0開始,可以自己定.例如:
Var A: Array[ 2..3 ] Of Integer ;Begin A[ 2 ] := 1 ; SetLength(A,3);//這裡會出錯,定長數組不能再分配End ;
從上面我們可以看到起始序號是2,但是步長是1,是不能改變的.為什麼我們看到很多數組的起始序號都是0呢?習慣而已.大家都習慣在廁所裡面去噓噓,而你一個人習慣在廣場上面噓噓,那麼大家都會說你不文明了.但是如果大家一開始都是在廣場上面噓噓的話,不說了太噁心了.
來看一個特殊的用法:
type THuangJacky = (hjA,hjB,hjC);const //用法1 B:array[0..2] of string= ('A','B','C'); //用法2 C:array[THuangJacky] of string= ('A','B','C');Var H:THuangJacky; S:string;Begin S:=B[Ord(H)]; S:=C[H]; //B[H] 和 C[1]都會出錯End ;
用法1 和用法2你覺得那種用著爽一些?
從上面例子可以看出來只要是序數類型都可以當數組的序號.但是我們用的時候序號就必須是聲明的那種序數類型,所以上面代碼注釋中才會寫出2種錯誤的情況.
不定長數組:動態數組,也就是聲明的時候沒有說長度是多少,在使用前必須聲明,長度可以再分配.序號必須從0開始.看個簡單的例子
Var A: Array Of Integer ;Begin SetLength( A, 3 ) ; //數組一共有3個元素 A[ 0 ] := 1 ; A[ 1 ] := 2 ; A[ 2 ] := 3 ; //A[3]沒有它,有它的話,你數一下幾個了?不會數數,那我推薦你去街道口小學看一下 SetLength( A, 4 ) ; //如果變長長度,直接增加後面的元素 A[ 3 ] := 4 ; //現在有它了. SetLength( A, 3 ) ; //如果長度變短,超出部分會被去掉 // A[3]又沒有它了End ;
有時候大家這樣要先設定長度,然後再賦值,是不是很麻煩?沒有一氣呵成的感覺.好吧,再說一招:
Type TA = Array Of Integer ;Var A: TA ;Begin A := TA.Create( 1, 2, 3 ) ; //此招請勿在D7上面使用 //這樣A[0]:=1,A[1]:=2,A[2]:=3End ;
2 一維和多維.
前面所有例子,我們都只是說了一維數組,要是現在我們想弄一個矩陣(多維陣列)怎麼辦?
Var A: Array [0.. 2, 0.. 2] Of Integer; B: Array [0.. 2] Of Array [0.. 2] Of Integer;Begin A[0, 0]:= 1; A[0][0]:= 1;End;
兩種方法都可以的.
Var B: Array Of Array Of Integer;Begin SetLength(B, 3, 3); // 3*3矩陣 // 如果要實現齒狀數組,必須這麼做 SetLength(B, 3); SetLength(B[0], 1); // * SetLength(B[1], 2); // ** SetLength(B[2], 3); // ***End;
接下來我們說說幾個關於數組中常用的函數:
第一個 複製數組
Var A, B: Array [0.. 1] Of Integer;Begin A[0]:= 1; A[1]:= 2; B:= A; B[0]:= 2; ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:1,B0:2End;
這個效果就是我們想要的,貌似沒有什麼好說的.如果是動態數組呢?
Var A, B: Array Of Integer;Begin SetLength(A, 2); SetLength(B, 2); A[0]:= 1; A[1]:= 2; B:= A; B[0]:= 2; ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:2,B0:2End;
現在怎麼辦?A和B被關聯到了一個地址了,其實現在我們可以使用Copy函數,對就是複製字串的那個函數:
Var A, B: Array Of Integer;Begin SetLength(A, 2); SetLength(B, 2); A[0]:= 1; A[1]:= 2; B:= Copy(A); // 整個數組都複製過去 B:= Copy(A, 0, 2); // 選擇性複製 B[0]:= 2; ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:1,B0:2End;
第二個 序號相關
函數Low()和High()值得信賴,不過我們需要注意的是,它們返回的類型是我們數組的序號的那個類型,並不都是Integer,如前面例子中的THuangJacky.
var A : array of array of string; I, J : Integer;begin SetLength(A, 10); for I := Low(A) to High(A) do begin SetLength(A[I], I); for J := Low(A[I]) to High(A[I]) do A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' '; end; end;
第三個 數組長度
Length()函數返回的就一定是是Integer了,因為個數不是整數難道還有半個麼?
Var A: Array Of Integer;Begin SetLength(A, 2); Length(A); // 返回2End;
最後說個問題我就不說了:
從上面那個複製的例子我們可以看出來什麼東西?
定長陣列變數就是一個變數,所以可以直接用:=來賦值,而動態陣列變數就是一個指標,如果用了:=來賦值2個變數就關聯在一起了.
Var A: Array [0.. 2] Of Integer; B: Array Of Integer;Begin ShowMessageFmt('A:%8x,A[0]:%8p', [Integer(@A), @A[0]]); // 一樣,從地址來看這個數組空間在棧上面 SetLength(B, 3); ShowMessageFmt('B:%8p,B[0]:%8p', [B, @B[0]]); // 一樣,這個資料空間在堆上面End;
我們看到A要取地址才和A[0]取地址一樣,那麼也就是說A就是A[0].
而B直接就和B[0]取地址一樣了,也就是說B就是B[0]的地址.
數組在記憶體中的分布:連續分布的,間隔就是每個元素的大小.
Var A: Array [0.. 2] Of Integer; B: Array Of Integer;Begin A[1]:= 123; // 從A也就是A[0]的地址上面 往下走4個直接 就是A[1] ShowMessageFmt('A[1]:%D,直接取值:%D', [A[1], PInteger(Integer(@A)+ 4)^]); // 一樣,都是123 SetLength(B, 3); B[2]:= 88; // 從B往下走8個位元組就是B[2] ShowMessageFmt('B[2]:%D,直接取值:%D', [B[2], PInteger(Integer(B)+ 8)^]); // 一樣,88End;
但是動態數組的結構和字元的結構就很像了:
| 位移 |
-8 |
-4 |
0~Length*元素大小-1 |
| 內容 |
32位引用次數 |
元素個數 |
實際內容 |
好了只能說這麼多了,我只理解了這麼多.
我是DH.