首先我们要知道什么是数组?数组是一堆相同特性数据的一个集合,也就是每个元素的类型必须是一样的,当然在其他一些弱语法的语言里面,数组的元素可以千奇百怪.
例子:
1
2
3
4
5
6
|
Var
A:
Array
[
0..2
]
Of
Integer
;
Begin
A[
0
] :=
1
;
A[
1
] :=
1.0
;
//这里是错的,因为每个元素都必须是Integer类型
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
//用法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
;
|
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
);
// 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位引用次数 | 元素个数 | 实际内容 |
好了只能说这么多了,我只理解了这么多.