技术交流,DH讲解.
首先我们要知道什么是数组?数组是一堆相同特性数据的一个集合,也就是每个元素的类型必须是一样的,当然在其他一些弱语法的语言里面,数组的元素可以千奇百怪. 例子:
1
2
3
4
5
6
|
Var
A: Array [ 0..2 ] Of Integer ;
Begin
A[ 0 ] := 1 ;
A[ 1 ] := 1.0 ;
End ;
|
Delphi中数组分类: 1 定长和不定长. 定长数组:也就是长度在声明的时候就确定了,后面是不能改变的,而在定长数组中,起始序号不必从0开始,可以自己定.例如:
1
2
3
4
5
6
|
Var
A: Array [ 2..3 ] Of Integer ;
Begin
A[ 2 ] := 1 ;
SetLength(A, 3 );
End ;
|
从上面我们可以看到起始序号是2,但是步长是1,是不能改变的.为什么我们看到很多数组的起始序号都是0呢?习惯而已.大家都习惯在厕所里面去嘘嘘,而你一个人习惯在广场上面嘘嘘,那么大家都会说你不文明了.但是如果大家一开始都是在广场上面嘘嘘的话,不说了太恶心了. 来看一个特殊的用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
type
THuangJacky = (hjA,hjB,hjC);
const
B: array [ 0..2 ] of string = ( 'A' , 'B' , 'C' );
C: array [THuangJacky] of string = ( 'A' , 'B' , 'C' );
Var
H:THuangJacky;
S: string ;
Begin
S:=B[Ord(H)];
S:=C[H];
End ;
|
用法1 和用法2你觉得那种用着爽一些? 从上面例子可以看出来只要是序数类型都可以当数组的序号.但是我们用的时候序号就必须是声明的那种序数类型,所以上面代码注释中才会写出2种错误的情况. 不定长数组:动态数组,也就是声明的时候没有说长度是多少,在使用前必须声明,长度可以再分配.序号必须从0开始.看个简单的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Var
A: Array Of Integer ;
Begin
SetLength( A, 3 ) ;
A[ 0 ] := 1 ;
A[ 1 ] := 2 ;
A[ 2 ] := 3 ;
SetLength( A, 4 ) ;
A[ 3 ] := 4 ;
SetLength( A, 3 ) ;
End ;
|
有时候大家这样要先设定长度,然后再赋值,是不是很麻烦?没有一气呵成的感觉.好吧,再说一招:
1
2
3
4
5
6
7
8
9
|
Type
TA = Array Of Integer ;
Var
A: TA ;
Begin
A := TA . Create( 1 , 2 , 3 ) ;
End ;
|
2 一维和多维. 前面所有例子,我们都只是说了一维数组,要是现在我们想弄一个矩阵(多维数组)怎么办?
1
2
3
4
5
6
7
|
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 ;
|
两种方法都可以的.
1
2
3
4
5
6
7
8
9
10
|
Var
B: Array Of Array Of Integer ;
Begin
SetLength(B, 3 , 3 );
SetLength(B, 3 );
SetLength(B[ 0 ], 1 );
SetLength(B[ 1 ], 2 );
SetLength(B[ 2 ], 3 );
End ;
|
接下来我们说说几个关于数组中常用的函数: 第一个 复制数组
1
2
3
4
5
6
7
8
9
|
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 ]]);
End ;
|
这个效果就是我们想要的,貌似没有什么好说的.如果是动态数组呢?
1
2
3
4
5
6
7
8
9
10
11
|
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 ]]);
End ;
|
现在怎么办?A和B被关联到了一个地址了,其实现在我们可以使用Copy函数,对就是复制字符串的那个函数:
1
2
3
4
5
6
7
8
9
10
11
12
|
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 ]]);
End ;
|
第二个 序号相关 函数Low()和High()值得信赖,不过我们需要注意的是,它们返回的类型是我们数组的序号的那个类型,并不都是Integer,如前面例子中的THuangJacky.
1
2
3
4
5
6
7
8
9
10
11
12
|
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了,因为个数不是整数难道还有半个么?
1
2
3
4
5
6
|
Var
A: Array Of Integer ;
Begin
SetLength(A, 2 );
Length(A);
End ;
|
最后说个问题我就不说了: 从上面那个复制的例子我们可以看出来什么东西? 定长数组变量就是一个变量,所以可以直接用:=来赋值,而动态数组变量就是一个指针,如果用了:=来赋值2个变量就关联在一起了.
1
2
3
4
5
6
7
8
|
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]的地址.
数组在内存中的分布:连续分布的,间隔就是每个元素的大小.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Var
A: Array [ 0 .. 2 ] Of Integer ;
B: Array Of Integer ;
Begin
A[ 1 ]:= 123 ;
ShowMessageFmt( 'A[1]:%D,直接取值:%D' , [A[ 1 ], PInteger( Integer (@A)+ 4 )^]);
SetLength(B, 3 );
B[ 2 ]:= 88 ;
ShowMessageFmt( 'B[2]:%D,直接取值:%D' , [B[ 2 ], PInteger( Integer (B)+ 8 )^]);
End ;
|
但是动态数组的结构和字符的结构就很像了:
偏移 |
-8 |
-4 |
0~Length*元素大小-1 |
内容 |
32位引用次数 |
元素个数 |
实际内容 |
SetLength: 设定数组长度 SetLength(MyArray, 5) // 设定MyArray数组长度为5 High: 传回注脚的最大值,如果参数为数组类型的话,则是返回数组索引的最大值 High(MyArray) // 返回值为5 Copy: 字符串截取函数 Copy('substring', 4, 3) // 返回值为‘str’
|
请发表评论