delphi 数组类型与数组指针的巧妙利用

{本例通过存取结构, 慢慢引入了数组类型与指针的一些使用方法; 其中六个小例子的测试内容和结果都是一样的. 
--------------------------------------------------------------------------------}

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

type {先定义结构和结构指针}
PMyRec = ^TMyRec;
TMyRec = record
F1: Char;
F2: Word;
end;

{用静态数组储存或读写结构很方便}
procedure TForm1.Button1Click(Sender: TObject);
var
ArrRec: array[0..2] of TMyRec;
i: Integer;
begin
{写入}
for i := 0 to 2 do
begin
ArrRec[i].F1 := Chr(i+65);
ArrRec[i].F2 := (i+1) * 10;
end;

{读取}
for i := 0 to Length(ArrRec) - 1 do
ShowMessageFmt('%s, %d', [ArrRec[i].F1, ArrRec[i].F2]);
end;

{这个只是定义了一块内存, 没用数组的概念, 有点麻烦}
procedure TForm1.Button2Click(Sender: TObject);
var
buf: PMyRec;
begin
GetMem(buf, SizeOf(TMyRec) * 3); {申请内存}

{写入}
buf^.F1 := 'A';
buf^.F2 := 10;
Inc(buf); {到下一个}
buf^.F1 := 'B';
buf^.F2 := 20;
Inc(buf);
buf^.F1 := 'C';
buf^.F2 := 30;

Dec(buf, 2); {回到开始}

{读取}
ShowMessageFmt('%s, %d', [buf^.F1, buf^.F2]);
Inc(buf); {到下一个}
ShowMessageFmt('%s, %d', [buf^.F1, buf^.F2]);
Inc(buf);
ShowMessageFmt('%s, %d', [buf^.F1, buf^.F2]);

Dec(buf, 2); {回到开始}
FreeMem(buf); {释放内存}
end;

{可以给结构定义一个数组类型}
procedure TForm1.Button3Click(Sender: TObject);
type
TArr = array of TMyRec;
var
buf: PMyRec;
i: Integer;
begin
GetMem(buf, SizeOf(TMyRec) * 3);

for i := 0 to 2 do
begin
TArr(buf)[i].F1 := Chr(i+65);
TArr(buf)[i].F2 := (i+1) * 10;
end;

for i := 0 to 2 do
ShowMessageFmt('%s, %d', [TArr(buf)[i].F1, TArr(buf)[i].F2]);

FreeMem(buf);
end;

{直接用动态数组也行}
procedure TForm1.Button4Click(Sender: TObject);
var
Arr: array of TMyRec;
i: Integer;
begin
SetLength(Arr, 3);
for i := 0 to 2 do
begin
Arr[i].F1 := Chr(i+65);
Arr[i].F2 := (i+1) * 10;
end;

for i := 0 to 2 do
ShowMessageFmt('%s, %d', [Arr[i].F1, Arr[i].F2]);
end;

{使用一个元素的数组指针, 这是很常用的}
procedure TForm1.Button5Click(Sender: TObject);
type
PArr = ^TArr;
TArr = array[0..0] of TMyRec;
var
buf: PArr;
i: Integer;
begin
GetMem(buf, SizeOf(TMyRec) * 3);

for i := 0 to 2 do
begin
buf^[i].F1 := Chr(i+65);
buf^[i].F2 := (i+1) * 10;
end;

{用这种方法不能像下面这样读写, 也就是 [] 中不能是超过 0 的常数, 但可以用变量}
{这也容易理解, 因为常量会直接编译到代码中, 在没有分配内存以前, 编译器不知道数组会更大}
{要解决这个问题需要用下一个方法}
// buf[0].F1 := 'A';
// buf[0].F2 := 10;
// buf[1].F1 := 'B';
// buf[1].F2 := 20;
// buf[2].F1 := 'C';
// buf[2].F2 := 30;

for i := 0 to 2 do
ShowMessageFmt('%s, %d', [buf[i].F1, buf[i].F2]);

FreeMem(buf);
end;

{使用一个超大的数组指针, Delphi 的 TList 类就是这么干的}
procedure TForm1.Button6Click(Sender: TObject);
type
PArr = ^TArr;
TArr = array[0..100000] of TMyRec; {不要担心内存暴涨, 使用时我们只用其指针}
var
buf: PArr;
i: Integer;
begin
GetMem(buf, SizeOf(TMyRec) * 3);

for i := 0 to 2 do
begin
buf^[i].F1 := Chr(i+65);
buf^[i].F2 := (i+1) * 10;
end;

{和上例不同的是, 下面的代码也可以}
// buf[0].F1 := 'A';
// buf[0].F2 := 10;
// buf[1].F1 := 'B';
// buf[1].F2 := 20;
// buf[2].F1 := 'C';
// buf[2].F2 := 30;

for i := 0 to 2 do
ShowMessageFmt('%s, %d', [buf[i].F1, buf[i].F2]);

FreeMem(buf);
end;

end.