Delphi 数组 详解

首先我们要知道什么是数组?数组是一堆相同特性数据的一个集合,也就是每个元素的类型必须是一样的,当然在其他一些弱语法的语言里面,数组的元素可以千奇百怪. 
例子:

?
1
2
3
4
5
6
Var
   A: Array [ 0..2  ] Of  Integer  ;
Begin
   A[ 0  ] := 1  ;
   A[ 1  ] := 1.0  ; //这里是错的,因为每个元素都必须是Integer类型
End  ;

 

Delphi中数组分类: 
定长和不定长
定长数组:也就是长度在声明的时候就确定了,后面是不能改变的,而在定长数组中,起始序号不必从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
   //用法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开始.看个简单的例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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  ;

 

有时候大家这样要先设定长度,然后再赋值,是不是很麻烦?没有一气呵成的感觉.好吧,再说一招:

?
1
2
3
4
5
6
7
8
9
Type
   TA = Array  Of  Integer  ;
Var
   A: TA ;
Begin
   A := TA . Create( 1 , 2 , 3  ) ;
   //此招请勿在D7上面使用
   //这样A[0]:=1,A[1]:=2,A[2]:=3
End  ;

 

一维和多维
前面所有例子,我们都只是说了一维数组,要是现在我们想弄一个矩阵(多维数组)怎么办?

?
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 ); // 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 ]]); // A0:1,B0:2
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 ]]); // A0:2,B0:2
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 ]]); // A0:1,B0:2
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); // 返回2
End ;
?
1
  

最后说个问题我就不说了: 
从上面那个复制的例子我们可以看出来什么东西? 
定长数组变量就是一个变量,所以可以直接用:=来赋值,而动态数组变量就是一个指针,如果用了:=来赋值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 ;
   // 从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 )^]); // 一样,88
End ;

但是动态数组的结构和字符的结构就很像了:

偏移 -8 -4 0~Length*元素大小-1
内容 32位引用次数 元素个数 实际内容

好了只能说这么多了,我只理解了这么多.

我是DH.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值