Delphi之动态数组使用总结
我所理解的Delphi中的数组类型
我所理解的Delphi中的数组类型数组可以使Object Pascal所拥有的任何数据类型,数组是⼀些数值的简单集合。
varMyArray: array[0..4] of Integer; { 声明⼀个数组包括5个整数数值}beginMyArray[0] := -200; { 通过操作符[]就可以访问每个数组元素}MyArray[1] := -100;MyArray[2] := 0;MyArray[3] := 100;MyArray[4] := 200;MyArray[0] := MyArray[1] + MyArray[4]; { MyArray[0]为-100}end;其MyArray在内存空间的分布,每个整数需要4个字节,因此整个数组将占20个字节的内存,如下:1、多维数组constCArray: array[0..4] of Integer = (-20, -100, 0, 100, 200);{ 数组常量的在声明的同时也要进⾏赋初值}varMyArray: array[0..2, 0..4] of Integer; { 两维数组的声明}UArray: array[10..20] of Integer; { 声明了⼀个下界10到上界20的11个元素的数组}X: Integer;begin{ 两种⽅法可以访问两维数组}X := MyArray[1][1] + MyArray[2][1]; { 1、[X][Y]访问}X := MyArray[1, 1] + MyArray[2, 1]; { 2、[X, Y]访问}{ 下⾯的访问超出了数组范围,将会提⽰“Constant expression violates subrange bounds”错误}X := MyArray[3, 1] + MyArray[0, 5]; {注意这两个元素超出数组声明的范围}end;其中MyArray被声明为⼀个⼆维数组,其在内存中的分布如下:2、上界与下界处理数组会经常⽤到上界(Low)和下界(High)函数。
Delphi模拟实现控件数组分析
个能够响应 由多个不同控件 引发的事件的处理程序方法成为可能。
分析 : o循环 用于遍历 当前 窗体 上所有属于TC mp n n类 Fr o o et
i f b t 类; o 使用控件数组可开发出一些小型游戏。 控件数组的灵活使 用能够大 的对 象 ;语句用于判 断某个对象是否属 于T utn 如果条件成 立 , 将 该 对象 的 C pin ̄性 修 改 为 B t n 。 过 上 述 分 析 , 则 at ) o T ut ’通 o 不 大提高 编程人员 的编程 效率 。 e h 未提 供专 门的控件 数组 , Dl i p 本文 主要讨 论的是 如何 在D lh 中模 拟实现控件数 组 。 ep i 这 最 ・难发现 , 种方 法有一 定局 限性 , 明显 的是 设计 人员并 不知道 C mp nn s ] o o etI [ 到底 代表哪一个控件 , 因此 只能用遍历的方法进行
C mp nns + ) o o e tn m】就可 以实现。 [ 从而提高程序 执行效率 , 同时也避 免 了编程上 的繁琐 问题 。 实 现方案如下 : 例如 : 在窗体上添 加若干个组件各 组件布置如 下图所示 :
件 以达到使用控件数组的 目的; 另外一种途径是 由用户 自己来开发 带数组性质 的VC 组件。 L 这两种方法对D L HI E P 的是初级入门者是 不现实 的。 使用T IT TRI 类 代码量大 , 以阅读 , LS S NG 难 使用时非常 吃力 ; 由用户 自己制作组件这又不是D L HI E P 初级使用者所能完成
筛 选 , 不 仅 影 响 了程 序 执 行 的 效 率 , 带 来 编 程 上 的繁 琐 问 题 。 这 也
2、控 件 数 组 原 理
要解决上述 问题 , 就要用 ̄TC mp nn类的C mp n nId x U o oet o o et e n 控 件 名 , 有 相 同 的属 性 , 行 相 似 的 操 作 , 具 执 同时 共 享 同样 的 事件 过 属性。 e h .中 , o o e t d x 在d l i 0 C mp n nl e 属性表示 当前窗体上属 于 p 7 n 程 。 区 分 控 件 数 组 中 的各 个 元 素 , 有 此 功 能 的 程 序 设 计 语 言 通 TC mp n n类 的某个对象在 C mp n t[数组 中的下标并且该 为 具 o oet o o e s] n I 常会把各元素的下标值传送给过程 , 过程从接收到的下标来区分不 属性是一个可读写属性 ; 该属性的默认值是该组件的添加次序 ( 从 同 的元 素 。 岍 始 计 数 )那 么就 可 以利 用 这 一 属 性 在 组件 生 成 时 将 同类 组 件 的 ,
Delphi动态数组、静态数组、TBytes的区别
Delphi动态数组、静态数组、TBytes的区别结论:1. 动态数组dArr1: array of byte,数组的名称是⼀个地址,该地址和数组的第⼀个元素的地址不⼀样。
该地址的值是第⼀个元素的地址。
dArr3: TBytes,和array of byte⼀样,只是⼀个别名,但是,有些函数的参数类型就是TBytes,你如果传array of byte的参数进去,会发⽣错误。
2. 静态数组(定义时即指定⼤⼩)dArr2: array[0..9] of byte,数组的名称是⼀个地址,该地址和数组的第⼀个元素的地址重合。
3. TMemorySteam列出内存流的原因是因为,通过内存流读写数组时,⾮常容易出错。
⽽且,array of byte的参数和TBytes参数会指向不同的函数体,所以需要重点列出。
演⽰界⾯:代码procedure TForm1.Button1Click(Sender: TObject);varsArr : array[0..9] of Byte; //静态数组pB : ^Byte;i : Integer;sTmp : string;beginMemo1.Lines.Append('');for i := 0to9dosArr[i] := ord('a') + i;sTmp := '';for i := 0to Length(sArr)-1dosTmp := sTmp + IntToStr(sArr[i]) + '';Memo1.Lines.Append('静态数组的内容');Memo1.Lines.Append(sTmp);pB := @sArr;sTmp := '静态数组的地址:' + IntToStr(Integer(pB));Memo1.Lines.Append(sTmp);pB := @(sArr[0]);sTmp := '静态数组第⼀个元素的地址:' + IntToStr(Integer(pB));Memo1.Lines.Append(sTmp);pB := @sArr;sTmp := '';for i := 0to Length(sArr)-1dobeginsTmp := sTmp + IntToStr(pB^) + '';pB := Pointer(LongWord(pB) + 1); //相当于 Inc(pB)end;Memo1.Lines.Append('以指针访问静态数组的内容');Memo1.Lines.Append(sTmp);end;procedure TForm1.Button2Click(Sender: TObject);vardArr : array of byte; //动态数组pB : ^Byte;i : Integer;sTmp : string;nValue : Integer;beginMemo1.Lines.Append('');SetLength(dArr, 10);for i := 0to Length(dArr)-1dodArr[i] := ord('A') + i;sTmp := '';for i := 0to Length(dArr)-1dosTmp := sTmp + IntToStr(dArr[i]) + '';Memo1.Lines.Append('动态数组的内容');Memo1.Lines.Append(sTmp);pB := @dArr;sTmp := '动态数组的地址:' + IntToStr(Integer(pB));Memo1.Lines.Append(sTmp);//可以看到,动态数据其实是⼀个地址,这个地址存放的值是数据第⼀个元素的地址 nValue := (PInteger(pB))^ ;sTmp := '动态数组地址中的内容:' + IntToStr(nValue);Memo1.Lines.Append(sTmp);pB := @(dArr[0]);sTmp := '动态数组第⼀个元素的地址:' + IntToStr(Integer(pB));Memo1.Lines.Append(sTmp);pB := @(dArr[0]);sTmp := '';for i := 0to Length(dArr)-1dobeginsTmp := sTmp + IntToStr(pB^) + '';Inc(pB);end;Memo1.Lines.Append('以指针访问动态数组的内容');Memo1.Lines.Append(sTmp);end;procedure TForm1.Button3Click(Sender: TObject);varstream : TMemoryStream;dArr1 : array of Byte; //动态数组dArr2 : array of Byte;//TBytes其实就是array of Byte,但是有了新名字,编译器就可找到以TBytes为参数//类型的重载函数了,这就是重新定义⼀个名字的意义//dArr1 : TBytes; //动态数组//dArr2 : TBytes;i : integer;sTmp : string;offset : Integer;count : Integer;beginMemo1.Lines.Append('');SetLength(dArr1, 10);for i := 0to Length(dArr1)-1dodArr1[i] := ord('A') + i;stream := TMemoryStream.Create;stream.SetSize(Length(dArr1));//注意,由于参数是 var类型,所以会取传⼊变量的地址进⾏作业,//所以dArr1[0]是正确的//⽽dArr1只是⼀个地址,这个地址的值才是数组的地址,所以传dArr1是错误的//w//stream.Write(dArr1[0], Length(dArr1)); //OK//stream.Write(dArr1, Length(dArr1)); //NG//stream.Write(Pointer(dArr1)^, Length(dArr1));//OK//stream.Write(TBytes(dArr1), Length(dArr1)); //OK//当参数的动态数组⽤TBytes转化时,实际执⾏的是下⾯这个函数,所以也不会出错//function TStream.Write(const Buffer: TBytes; Count: Longint): Longint;//begin//Result := Write(Buffer, 0, Count);//end;//所以,下⾯这样调⽤也是OK的stream.Write(TBytes(dArr1), 0, Length(dArr1)); //OKSetLength(dArr2, 10);stream.Position := 0;stream.Read(dArr2[0], 10); //OK//stream.Read(Pointer(dArr2)^, 10); //OK//stream.Read(TBytes(dArr2), 10); //OK//stream.Read(TBytes(dArr2), 0, 10); //OK//dArr2被定义成TBytes,OK; 定义为 array of byte, NG//stream.Read(dArr2, 10);//stream.Read(dArr2, 0, 10);sTmp := '';for i := 0to Length(dArr1)-1dobeginsTmp := sTmp + IntToStr(dArr1[i]) + '';end;Memo1.Lines.Append('数组1的内容');Memo1.Lines.Append(sTmp);sTmp := '';for i := 0to Length(dArr2)-1dobeginsTmp := sTmp + IntToStr(dArr2[i]) + '';end;Memo1.Lines.Append('内存流读出的内容');Memo1.Lines.Append(sTmp);end;。
delphi stralloc 使用方法
delphi stralloc 使用方法1. 简介Delphi是一种面向对象的编程语言,广泛用于Windows平台上的应用程序开发。
stralloc是Delphi中用于动态分配字符串内存的函数。
本文将介绍stralloc的使用方法,包括定义、分配、释放和使用动态字符串。
2. 定义动态字符串在Delphi中,可以使用stralloc函数来定义动态字符串。
stralloc函数的原型如下:function StrAlloc(Size: Cardinal): PChar;其中,Size参数指定了要分配的字符串的大小,单位是字节。
函数返回一个指向分配的内存的指针。
下面是一个示例代码,演示了如何定义一个动态字符串:varstr: PChar;beginstr := StrAlloc(10);// 在这里可以使用str指针来操作动态字符串StrDispose(str);end;上述代码中,我们定义了一个名为str的指针,然后使用StrAlloc函数分配了10个字节的内存。
注意,在使用完动态字符串后,我们需要使用StrDispose函数来释放内存。
3. 分配动态字符串在上一节中,我们介绍了如何定义动态字符串。
接下来,我们将介绍如何给动态字符串分配内存。
在Delphi中,可以使用StrNew函数来分配动态字符串的内存。
StrNew函数的原型如下:function StrNew(const Str: PChar): PChar;StrNew函数接受一个已有的字符串,然后为该字符串分配内存,并返回一个指向该内存的指针。
下面是一个示例代码,演示了如何分配动态字符串:varstr: PChar;beginstr := StrNew('Hello, World!');// 在这里可以使用str指针来操作动态字符串StrDispose(str);end;上述代码中,我们使用StrNew函数为字符串”Hello, World!“分配了内存,并将返回的指针赋值给str变量。
Delphi的参数传递约定以及动态参数个数(转载笔记)
Delphi的参数传递约定以及动态参数个数(转载笔记)《Delphi中的参数传递约定概述》由于Delphi太好⽤了以⾄于⼤多数Delphi fans对Delphi约定都没什么认识...抱歉其实⼤部分⼈的确是这样的这⾥写下⼀篇浊⽂仅供⼤家参考-转载保留版权.谢谢⼤家⽀持1.register-Delphi默认模式参数传递模式...前三个数据.eax,edx,ecx...超过三个参数部分.放在堆栈传递其他的⽅法和...和stdcall⼀样...函数⾃⼰恢复堆栈按照这个传递模式,所以说..这样效果编译器会更容易优化⼀些?呵呵procedure XorMemory(lpMemory: Pointer; bKey: BYTE; dwLen: DWORD);beginwhile (dwLen > 0) dobeginPBYTE(lpMemory)^ := PBYTE(lpMemory)^ xor bKey;Inc(PBYTE(lpMemory));Dec(dwLen);end;end;2.pascal-⽬前基本上不使⽤了3.cdecl-C语⾔调⽤约定(从右向左压栈.调⽤者恢复堆栈)这个模式在Delphi下是⼀个很争议的话题..怎么说呢..⽐如说wsprintf等函数都是错误的翻译...C\C++下是采⽤cdecl调⽤约定,⽽Delphi下全部翻译成stdcall模式...⽽且C\C++总是配合可变参数⼀起使⽤的...⽽Delphi下也是有可变参数标记的⼀般⽤户很少去关注如何使⽤罢了具体看⼀下windows.pasfunction wsprintf(Output: PChar; Format: PChar): Integer; stdcall;这⾥的声明类型完全是错误的...如果想要和C⼀样的⽅式function wsprintf(Output: PChar; Format: PChar): Integer; cdecl; varargs; external user32 name 'wsprintfA';function DbgPrint(Format:PChar): NTSTATUS; cdecl; varargs; external NtKernel name 'DbgPrint';function _snprintf(buffer: PChar; nsize: Integer; const fmt: PChar): Integer; cdecl; varargs; external NtKernel name '_snprintf'; ⾃⼰单独写⼀个函数声明...即可...你可以变参调⽤了...使⽤的时候...和C\C++下使⽤完全⼀样这⾥有⼀个窍门...这样的函数我们如何声明函数类型?找了⼤量的资料还是没招.不知道如何测试居然测试成功了...这叫啥?不知道program Project2;usesWindows;// 注意看下⾯--cdecl varargs;之间是没有;号的typeTwsprintfA = function(Output: PAnsiChar; Format: PAnsiChar): Integer; cdecl varargs;varfnwsprintfA: TwsprintfA;szBuffer: Array[0..MAX_PATH] Of Char;begin@fnwsprintfA := GetProcAddress(LoadLibrary('user32'), 'wsprintfA');fnwsprintfA(szBuffer, 'Id: %s, Age: %d', 'Anskya', 18);MessageBox(0, szBuffer, 'By Anskya', 0);end.4.stdcall-标准调⽤约定(从右向左压栈.函数⾃⼰恢复堆栈)这个...基本上api都是采⽤如此调⽤模式..编写动态运⾏库的⽐较重要的约定5.safecall-Delphi不⽀持..唉~牧龙⿏⼤⽜抱歉我解决半天也没搞定这个约定C\C++⽀持,其实和register约定出奇的相似.⽀持传递参数的寄存器不⼀样.Delphi编写变长参数的cdecl函数学过C语⾔的⼈都知道,printf的参数是不固定的,这种参数形式叫做变长参数。
Delphi中资源文件的使用(静态,动态)
[转]Delphi中资源文件的使用在Delphi中,生成一个Appliction工程时,会默认生成一个与工程同名的资源文件,即使删除也会再度创建,但是这个资源文件中只有一个图标和一个版本信息。
通常情况下,我们还需要更多的多种多样的资源,虽然可以在IDE中载入并编译到EXE文件中去,但是有时我们需要将资源与EXE分开,以便生成多语言程序或将程序改为其它语言(如汉化)。
Delphi附带的ImageEdit可以编辑资源文件,但只能编辑位图、图标和光标,无法加入字符串资源,而且只持256色的图像。
为了将更多种类的资源,只有编写资源脚本或者使用其它资源编辑器,如Vis ual Stadio 6。
不过,Visual Stadio 6编辑的资源文件中包含了C++头文件定义,并且支持的具体资源类型较多,在Delphi中是无法识别的。
只好选择编写资源脚本了,资源脚本文件扩展名为.RC,可以用纯文本编辑器编写。
如下面是两个图标与两个字符串的脚本:COMPUTER RCDATA"computer.ico" /* Delphi中只支持RCDATA类型*/WINDOWSXP RCDATA"XP.ico"STRINGTABLEBEGIN1 "computer(电脑)"2 "Windows XP"END将其保存为MyRes.rc,需要注意的是,这里包含了两个图标,注意文件名及路径(这里是与文件同一目录)。
在命令提示符窗口中将目录切换到MyRes.rc所在的路径,运行brcc32 MyRes.rc,其中brcc 32.exe是Delphi附带的资源编译工具。
如果想将资源文件生成其中扩展名的文件(如.DLL),可以增加-fo参数,如:brcc32 MyRes.rc –of MyRes.dll。
接下来是对资源的引用,引用方法有静态与动态两种,静态引用就是将资源文件包含到源码中编译到EXE中去;动态引用则是把资源文件当成DLL动态装载。
Delphi中的动态数组总结
Delphi中的动态数组总结今天做的⼀个项⽬中要使⽤⼀⼤串数据进⾏处理。
如何对这⼀系列的数据进⾏保存成为⼀个⾸要的问题。
唉,Delphi啊,你何时才能⽀持泛型啊。
在C#,C++这都不是问题了啊。
在Delphi⾥只有TStringList这个容器可以使⽤,但是它是处理字符串的。
⼀进⼀出,需要⼤量的typecast时间。
⽤链表??不值得。
上⽹⼀查,呵呵,可以⽤动态数组。
看来我还是⼀个新⼿,这个东西我都不知道啊。
啥时候Delphi有了这个玩意了。
vari:array of integer;beginSetLength(i,length);//设置动态数组的长度以后就可以像正常数组那样操作有了动态数组就可以随时设置数组的⼤⼩,不会像以前那样事先定义数组的⼤⼩,对资源造成浪费。
动态数组的本质还是指针,上⾯的例⼦。
i 就是⼀个指针类型。
可以将两个动态数组之间进⾏引⽤赋值,当然了我们也可以将其复制给⼀个Pointer,只不过意义不⼤罢了。
varp:Pointer;i,j:Array of integer;beginSetLength(i,20);//分配内存空间i[0] := 22;i := j;//此时,i,j都同时指向了那段动态数组的存p := i; //没有实际意义,只是证明了i 是指针类型//释放⼯作end;使⽤完了内存当然需要释放了,否则会造成内存泄露。
动态数组使⽤了 reference-counting 技术,所以在使⽤完后,只需将其赋值为nil即可。
-------------------------------------------------------------------⾃从有了动态数组,链表除了在教科书⾥出现外,已经很少在实际编程中被使⽤了,事实也是如此,数组的确⽐传统链表快得多,⽽且也⽅便的多。
从 Delphi4起,开始了内建各种类型的动态数组⽀持。
但是,对我们来说动态数组⽀持似乎做的不够彻底,因为Delphi竟然连删除、插⼊、移动连续元素的函数都没有提供,让⼈使⽤起来总觉得不够爽!!! J 。
Delphi动态与静态调用DLL(最好的资料)
Delphi动态与静态调用DLL(最好的资料)摘要:本文阐述了 Windows 环境下动态链接库的概念和特点,对静态调用和动态调用两种调用方式作出了比较,并给出了 Delphi 中应用动态链接库的实例。
一、动态链接库的概念动态链接库( Dynamic Link Library ,缩写为 DLL )是一个可以被其它应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源。
动态链接库文件的扩展名一般是 dll ,也有可能是 drv 、 sys 和 fon ,它和可执行文件( exe )非常类似,区别在于 DLL 中虽然包含了可执行代码却不能单独执行,而应由 Windows 应用程序直接或间接调用。
动态链接是相对于静态链接而言的。
所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。
换句话说,函数和过程的代码就在程序的 exe 文件中,该文件包含了运行时所需的全部代码。
当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。
而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。
仅当应用程序被装入内存开始运行时,在 Windows 的管理下,才在应用程序与相应的 DLL 之间建立链接关系。
当要执行所调用 DLL 中的函数时,根据链接产生的重定位信息, Windows 才转去执行 DLL 中相应的函数代码。
一般情况下,如果一个应用程序使用了动态链接库, Win32 系统保证内存中只有 DLL 的一份复制品,这是通过内存映射文件实现的。
DLL 首先被调入 Win32 系统的全局堆栈,然后映射到调用这个 DLL 的进程地址空间。
在 Win32 系统中,每个进程拥有自己的 32 位线性地址空间,如果一个 DLL 被多个进程调用,每个进程都会收到该 DLL 的一份映像。
Delphi常用技巧
Delphi常用技巧在网上行走时,经常会看到弹出的桌面小窗体,有时做广告,有时向你致以节日的问候;人们称其为桌面小精灵;有的桌面小精灵会自动移动,有的固定在屏幕的某一角落,动画闪烁,煞是迷人。
本人用Delphi 制作了一款桌面小精灵,愿与大家共享。
桌面小精灵的实现功能:当运行时,在屏幕的左下角显示一无边框、无标题栏的小窗体,并自动向屏幕的右上角移动,窗体上的小精灵——可爱的马先生,一会跃起,高呼“马到成功!”,一会含情脉脉地向你招手“再见”;同时,还不断地闪烁显示当前时间,时刻提醒你抓紧时间呦!当你嫌它碍事时,你可以按下鼠标左键,将它拖到任意位置。
如果你厌烦它不停移动,你可以双击鼠标左键,它会老老实实地呆在原地不动,只要你用鼠标轻轻一点,它又会高高兴兴地上路,当你单击“再见”时,桌面小精灵就会消失,你不想一试身手吗?请跟我来!运行后效果图生成一窗体,设置窗体属性如下:Name属性为Form1,BorderStyle属性为bsNone,FormStyle属性为StyOnTop,Height属性值240,Width属性值209。
窗体上分别添加组件,设置属性如下:(1)添加两个Image组件,Name属性分别设为Image1、Image2,Align属性均设为alClient (以使Image 组件充满整个窗体),Image1的Enabled为False,Image2的Enabled为True,然后通过Picture属性为Image1、Image2添加图片(适合的图片格式:BMP、JPG )。
(2)在Image上再添加两个Timer组件,Name属性分别为Timer1、Timer2,Enabled属性均为True,Interval 属性均为1000毫秒。
(3)在Image上再添加一个Label组件,Name:=Label1,Caption:=“马到成功!”,Enabled:=True,Font属性为“华文行楷,粗斜体,三号字,红色”(根据你的图片设置适当的字体、字号、字体颜色)。
Delphi编程中动态菜单要点归纳
Delphi编程中动态菜单要点归纳一、创建菜单并添加项目在设计程序时,有时需要动态创建菜单, 通常使用以下的语句:PopupMenu1 := TPopupMenu.Create(Self);Item := TMenuItem.Create(PopupMenu1);Item.Caption := '菜单一';Item.OnClick := MenuItem1Click;PopupMenu1.Items.Add(Item);Item := TMenuItem.Create(PopupMenu1);Item.Caption := '菜单二';Item.OnClick := MenuItem2Click;PopupMenu1.Items.Add(Item);Item := TMenuItem.Create(PopupMenu1);Item.Caption := '菜单三';Item.OnClick := MenuItem3Click;PopupMenu1.Items.Add(Item);Item := TMenuItem.Create(PopupMenu1);Item.Caption := '-'; // 增加一个分割条PopupMenu1.Items.Add(Item);Item := TMenuItem.Create(PopupMenu1);Item.Caption := '菜单四';Item.OnClick := MenuItem4Click;PopupMenu1.Items.Add(Item);还可以使用一种更快捷的方法达到同样的目的, 那就是用NewLine 和NewItem, 方法如下:PopupMenu1 := TPopupMenu.Create(Self);with PopUpMenu1.Items dobeginAdd(NewItem('菜单一',0,False,True,MenuItem1Click,0,'MenuItem1'));Add(NewItem('菜单二',0,False,True,MenuItem2Click,0,'MenuItem2'));Add(NewItem('菜单三',0,False,True,MenuItem3Click,0,'MenuItem3'));Add(NewLine); // 增加一个分割条Add(NewItem('菜单四',0,False,True,MenuItem4Click,0,'MenuItem4'));end;二、插入菜单项上述方法是在创建完菜单后,紧接着为其添加菜单项目。
Delphi-基础(常量、集合、数组[动态数组、多维数组])
Delphi-基础(常量、集合、数组[动态数组、多维数组])⼀、常量 1、常量定义:⼀开始定义好的值,以后在程序的运⾏过程中不允许改变1const2 Pi : Double = 3.141592; //定义为常量3{常量的定义⽅式,可以不进⾏类型的声明,编译器会根据具体值决定常量的的类型}4 Pi2 = 3.1415;2、常量使⽤ 枚举:常量集 type 枚举名=(标识符1,标识符2,标识符3,......)1type2{正常情况下,枚举类型的索引是从0开始}3 EColors = (RED,GREEN,BLUE);4 EWeek = (SUN=7,MON=1,TUE=2,WED=3,THU=4,FRI=5,SAT=6);5var6 Color : EColors;7 Week : EWeek;89begin10 Color := EColors.RED;11 Week := EWeek.SUN;12 Writeln(Ord(Color),',',Ord(Week));13 REDln;14end.⼆、⼦界 使⽤:为了防治出现越界 注意事项: 1、⼦界要求上界和下界必须是有序的数据类型整数、字符、枚举 2、⼦界的上界⼤于或者等于下界 格式:type ⼦界1{定义格式}2type3{枚举}4 EColors = (RED,GREEN,BLUE);5{⼦界}6 TSubBoundNumber = 1..10;7 TSubBoundChar = 'a'..'z';8910begin11 Writeln(Low(TSubBoundNumber)); //下界12 Writeln(High(TSubBoundChar)); //上界13 REDln;14end.打印出闰年还是平年,每个⽉的天数和所属季节1{打印出闰年还是平年,每个⽉的天数和所属季节}2type3{⼦界}4 TSubBoundMonths = 1..12;5{枚举}6 ESeason = (Spring,Summer,Autumn,Winter);78var9 Season : ESeason;1415procedure SubBound();16begin17 Writeln('请输⼊⼀个年份:');18 REDln(User_Year);19{默认为闰年}20 Is_Leap_Year := True;21while Is_Leap_Year do22begin23if (User_Year mod4) = 0then begin24if not((User_Year mod100) = 0) then begin25 Writeln('闰年',User_Year);26 Is_Leap_Year := False;27end;28end;29if (User_Year mod400) = 0then begin30 Writeln('闰年',User_Year);31 Is_Leap_Year := False;32end33else begin34 Is_Leap_Year := False;35 Writeln('平年',User_Year)3637end;38end;3940end;41procedure Months();42begin43{季节}44 Writeln('请输⼊⼀个⽉份:');45 REDln(User_Month);46begin47if (User_Month >= Low(TSubBoundMonths)) and (User_Month <= High(TSubBoundMonths)) then48if (User_Month >= 1) and (User_Month <= 3) then begin49 Writeln('当前季节为春季');50case User_Month of511 : begin52 Writeln('31天');53end;542 : begin55if Is_Leap_Year then begin56 Writeln('29天');57end else begin58 Writeln('28天');59end;60end;613 : begin62 Writeln('31天');63end;64end;65end;6667end;68end;6970begin71// Writeln(Low(TSubBoundNumber)); //下界72// Writeln(High(TSubBoundChar)); //上界7374 SubBound();75 Months();76 REDln;77end.View Code三、集合集合是由具有某些共同特征的元素结构的⼀个整体。
Delphi 第7章 数组与记录类型
7.1.2 动态数组 2. 多维动态数组
Type 〈数组类型标识符〉=array of array of … array of 〈基类型〉; Var 〈变量名〉:〈动态数组类型标识符〉; 或 Var 〈动态数组变量名〉: array of array of … array of 〈基类型〉;
例如,如下声明了一个二维动态数组变量
第7章 数组与记录类型 数组是一些具有相同类型的元素按一定顺序组 成的序列。数组中的每一个数据元素都可以 通过数组名唯一一个索引号来存取,它们被 顺序地安排在内存中的一段连续的存储区中。 7.1 数组及其应用 7.2 记录类型
1
7.1 数组及其应用 在Delphi 5/6版本中的Object Pascal引入了动 态数组,数组的内存分配不再局限于静态的, 可以采用动态方式为数组分配内存区。因此, 数组可分为静态数组和动态数组两种类型。
21
【例7-4】结合数组类型和记录类型编写一个计 算学生成绩的程序。 如程序所示
22
谢谢观看!
Delphi
23
2
7.1.1 静态数组 静态数组在程序初始化时必须分配内存单元, 明确其固定的大小和元素的数据类型。 1. 一维静态数组 数组通常可分为一维、二维和多维数组,在 Object Pascal中,定义一个一维数组类型, 其声明格式为: Type 〈数组类型标识符〉=array[〈下标类型〉] of 〈基类型〉;
9
【例7-1】利用数组求出任意10个数中的最大及 最小值。 如程序所示 【例7-2】利用二维数组建立一个8×8的方阵, 该矩阵对角线元素为8,其余元素为1,结果 显示在列表组件ListBox1中。 如程序动态数组 一维动态数组的声明格式为: Type 〈数组类型标识符〉=array of 〈基类型〉; 也可在变量声明中直接声明动态数组,其格式 为: Var 〈变量名〉: array of 〈基类型〉;
delphi 中集合用法
delphi 中集合用法Delphi 中集合用法Delphi 是一种面向对象的编程语言,它提供了许多集合类来帮助开发人员管理数据。
在本文中,我们将介绍 Delphi 中常用的几种集合类及其用法。
一、TList 类TList 是 Delphi 中最常用的集合类之一。
它是一个动态数组,可以存储任意类型的数据。
以下是 TList 类的基本用法:1. 创建 TList 对象要创建 TList 对象,可以使用以下代码:varMyList: TList;beginMyList := TList.Create; // 创建一个空的 TList 对象end;2. 添加元素要向 TList 中添加元素,可以使用 Add 方法:MyList.Add('Hello');MyList.Add('World');3. 访问元素要访问 TList 中的元素,可以使用 [] 运算符或 Items 属性:varS: string;beginS := MyList[0]; // 获取第一个元素S := MyList.Items[1]; // 获取第二个元素end;4. 删除元素要从 TList 中删除元素,可以使用 Delete 方法:MyList.Delete(0); // 删除第一个元素5. 清空列表要清空整个列表,可以使用 Clear 方法:MyList.Clear;二、TStringList 类TStringList 是一个特殊的 TList 类,它只能存储字符串类型的数据。
以下是 TStringList 类的基本用法:1. 创建 TStringList 对象要创建 TStringList 对象,可以使用以下代码:varMyStringList: TStringList;beginMyStringList := TStringList.Create; // 创建一个空的 TStringList 对象end;2. 添加元素要向 TStringList 中添加元素,可以使用 Add 方法:MyStringList.Add('Hello');MyStringList.Add('World');3. 访问元素要访问 TStringList 中的元素,可以使用 [] 运算符或 Strings 属性:varS: string;beginS := MyStringList[0]; // 获取第一个元素S := MyStringList.Strings[1]; // 获取第二个元素end;4. 删除元素要从 TStringList 中删除元素,可以使用 Delete 方法:MyStringList.Delete(0); // 删除第一个元素5. 清空列表要清空整个列表,可以使用 Clear 方法:MyStringList.Clear;6. 排序列表要对整个列表进行排序,可以使用 Sort 方法:MyStringList.Sort;三、TObjectList 类TObjectList 是一个 TList 类的扩展版本,它只能存储 TObject 类型的数据。
Delphi-数组详解
Delphi-数组详解技术交流,DH讲解.⾸先我们要知道什么是数组?数组是⼀堆相同特性数据的⼀个集合,也就是每个元素的类型必须是⼀样的,当然在其他⼀些弱语法的语⾔⾥⾯,数组的元素可以千奇百怪.例⼦:VarA: Array[ 0..2 ] Of Integer ;BeginA[ 0 ] := 1 ;A[ 1 ] := 1.0 ; //这⾥是错的,因为每个元素都必须是Integer类型End ;Delphi中数组分类:1 定长和不定长.定长数组:也就是长度在声明的时候就确定了,后⾯是不能改变的,⽽在定长数组中,起始序号不必从0开始,可以⾃⼰定.例如:VarA: Array[ 2..3 ] Of Integer ;BeginA[ 2 ] := 1 ;SetLength(A,3);//这⾥会出错,定长数组不能再分配End ;从上⾯我们可以看到起始序号是2,但是步长是1,是不能改变的.为什么我们看到很多数组的起始序号都是0呢?习惯⽽已.⼤家都习惯在厕所⾥⾯去嘘嘘,⽽你⼀个⼈习惯在⼴场上⾯嘘嘘,那么⼤家都会说你不⽂明了.但是如果⼤家⼀开始都是在⼴场上⾯嘘嘘的话,不说了太恶⼼了.来看⼀个特殊的⽤法:typeTHuangJacky = (hjA,hjB,hjC);const//⽤法1B:array[0..2] of string= ('A','B','C');//⽤法2C:array[THuangJacky] of string= ('A','B','C');VarH:THuangJacky;S:string;BeginS:=B[Ord(H)];S:=C[H];//B[H] 和 C[1]都会出错End ;⽤法1 和⽤法2你觉得那种⽤着爽⼀些?从上⾯例⼦可以看出来只要是序数类型都可以当数组的序号.但是我们⽤的时候序号就必须是声明的那种序数类型,所以上⾯代码注释中才会写出2种错误的情况.不定长数组:动态数组,也就是声明的时候没有说长度是多少,在使⽤前必须声明,长度可以再分配.序号必须从0开始.看个简单的例⼦VarA: Array Of Integer ;BeginSetLength( 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 ;有时候⼤家这样要先设定长度,然后再赋值,是不是很⿇烦?没有⼀⽓呵成的感觉.好吧,再说⼀招:TypeTA = Array Of Integer ;VarA: TA ;BeginA := TA.Create( 1, 2, 3 ) ;//此招请勿在D7上⾯使⽤//这样A[0]:=1,A[1]:=2,A[2]:=3End ;2 ⼀维和多维.前⾯所有例⼦,我们都只是说了⼀维数组,要是现在我们想弄⼀个矩阵(多维数组)怎么办?VarA: Array [0.. 2, 0.. 2] Of Integer;B: Array [0.. 2] Of Array [0.. 2] Of Integer;BeginA[0, 0]:= 1;A[0][0]:= 1;End;两种⽅法都可以的.VarB: Array Of Array Of Integer;BeginSetLength(B, 3, 3); // 3*3矩阵// 如果要实现齿状数组,必须这么做SetLength(B, 3);SetLength(B[0], 1); // *SetLength(B[1], 2); // **SetLength(B[2], 3); // ***End;接下来我们说说⼏个关于数组中常⽤的函数:第⼀个复制数组VarA, B: Array [0.. 1] Of Integer;BeginA[0]:= 1;A[1]:= 2;B:= A;B[0]:= 2;ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:1,B0:2End;这个效果就是我们想要的,貌似没有什么好说的.如果是动态数组呢?VarA, B: Array Of Integer;BeginSetLength(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函数,对就是复制字符串的那个函数:VarA, B: Array Of Integer;BeginSetLength(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.varA : array of array of string;I, J : Integer;beginSetLength(A, 10);for I := Low(A) to High(A) dobeginSetLength(A[I], I);for J := Low(A[I]) to High(A[I]) doA[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';end;end;第三个数组长度Length()函数返回的就⼀定是是Integer了,因为个数不是整数难道还有半个么?VarA: Array Of Integer;BeginSetLength(A, 2);Length(A); // 返回2End;最后说个问题我就不说了:从上⾯那个复制的例⼦我们可以看出来什么东西?定长数组变量就是⼀个变量,所以可以直接⽤:=来赋值,⽽动态数组变量就是⼀个指针,如果⽤了:=来赋值2个变量就关联在⼀起了. VarA: Array [0.. 2] Of Integer;B: Array Of Integer;BeginShowMessageFmt('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]的地址.数组在内存中的分布:连续分布的,间隔就是每个元素的⼤⼩.VarA: Array [0.. 2] Of Integer;B: Array Of Integer;BeginA[1]:= 123;// 从A也就是A[0]的地址上⾯往下⾛4个直接就是A[1]ShowMessageFmt('A[1]:%D,直接取值:%D', [A[1], PInteger(Integer(@A)+ 4)^]);// ⼀样,都是123SetLength(B, 3);B[2]:= 88;// 从B往下⾛8个字节就是B[2]ShowMessageFmt('B[2]:%D,直接取值:%D', [B[2], PInteger(Integer(B)+ 8)^]); // ⼀样,88End;但是动态数组的结构和字符的结构就很像了:偏移-8-40~Length*元素⼤⼩-1内容32位引⽤次数元素个数实际内容好了只能说这么多了,我只理解了这么多.我是DH.。
delphi 调用约定,数组
声明过程或函数时,可以指定调用约定(calling convention)。
指定调用约定可以使用的指示字包括register、pascal、cdecl、stdcall以及safecall。
例如,function MyFunction(X, Y: Real): Real; cdecl;...调用约定决定了传递给例程的参数的顺序,还影响参数从栈中的解除、参数传递时对寄存器的使用以及处理错误和异常等。
缺省的调用约定是register。
·register和pascal约定自左向右传递参数;也就是说,最左边的参数最先求值并传递,最右边的参数最后求值并传递。
cdecl、stdcall和safecall约定自右向左传递参数。
·除cdecl外,对其他所有的约定,过程和函数在返回时即从栈中删除参数。
对cdecl约定,则由调用者在调用返回时从栈中删除参数。
·register约定最多可以使用三个CPU寄存器传递参数,而其他的约定都通过栈传递所有的参数。
·safecall约定实现了异常防火墙。
在Windows中,这一实现在内部处理COM错误通知。
下表是调用约定的简要概括:指示字参数顺序参数删除者是否用寄存器传递参数?register从左到右例程是pascal从左到右例程否cdecl从右到左调用者否stdcall例程否safecall从右到左例程否缺省的register约定是效率最高的,因为它通常避免了栈中新帧的创建。
(对公布属性published properties的访问必需使用register约定。
)调用来自用C或C++编写的共享库的函数时,cdecl约定是很有用的,而对外部代码的调用,一般而言,推荐使用stdcall和safecall约定。
在Windows中,操作系统API函数使用的是stdcall和safecall约定。
其他操作系统通常使用cdecl约定。
(注意,stdcall约定比cdecl约定具有更高的效率。
DELPHI编程技巧集锦(4)
ShGetFileInfo(PChar(Ext), 0, SHFileInfo,
SizeOf(SHFileInfo), SHGFI_SMALLICON or
SHGFI_SYSICONINDEX or SHGFI_TYPENAME);
result:= SHFileInfo.iIcon;
end;
下面将系统图象列表连接到TListView控件上。注意我们设置动态建立的图象列表的ShareImages属性为真,这可以确保我们不试图释放Windows系统拥有的图象。在窗体的OnCreate事件处理程序中加上:
with YourListView do
begin
SmallImages := TImageList.CreateSize(16,16);
if (ssCtrl in Shift) and (chr(Key) in ['A', 'a']) then ShowMessage('Ctrl-A');
OnKeyDown事件处理程序将捕获击键,并执行指定的代码。
六、
A
假如编写一个衍生类的初始化例程,并希望将参数传递给基类的初始化例程,一般使用如下方法:
J
假如你需要存取WIN95的系统图象列表,这里给出具体方法。第一个函数将系统图象列表的索引保存到一个特殊类型的文件中:
function GetFileIcoIndex(Filename:String):Integer;
var
Ext: String;
ShFileInfo: TSHFILEINFO;
begin
上述代码只能动态地开关一个菜单的菜单条目,如果要同时动态改变所有菜单的菜单条目,需要使用窗体的Components属性,代码如下:
Delphi之动态数组使用总结
Delphi之动态数组使用总结第一篇:Delphi之动态数组使用总结Delphi之动态数组使用总结传统的Pascal 语言其数组大小是预先确定的,当你用数组结构声明数据类型时,你必须指定数组元素的个数。
专业程序员也许知道些许动态数组的实现技术,一般是采用指针,用手工分配并释放所需的内存。
Delphi 4中增加了非常简单的动态数组实现方法,实现过程效仿我前面讲过的动态长字符串。
与长字符串一样,动态数组的内存动态分配并且引用记数,不过动态数组不支持copy-on-write 技术。
这不是个大问题,因为你可以把变量值设置为nil释放数组内存。
这样你就可以声明一个不指定元素个数的数组,并用SetLength 过程给数组分配一个特定大小的内存,SetLength 过程还可以改变数组大小而不影响其内容,除此外还有一些字符串过程也可用于数组,如Copy 函数。
以下摘录的代码突出了一点,这就是:定义数组后必须先为它分配内存,然后才能开始使用:procedure TForm1.Button1Click(Sender: TObject);var Array1: array of Integer;begin Array1 [1] := 100;// error SetLength(Array1, 100);Array1 [99] := 100;// OK...end;如果你只定义一个数组元素个数,那么索引总是从0开始。
Pascal 中的普通数组既能用不为零的下标,也能用非整数的下标,但动态数组均不支持这两种下标。
象普通数组一样,你可以通过Length、High和Low 函数了解到动态数组的状况,不过对于动态数组,Low 函数返回值总是0,High函数返回数组大小减1,这意味着空的动态数组其函数High返回值是-1,这是一个很怪的值,因为它比Low的返回值还小。
图 8.1: 例 DynArr 窗体以上作了简短的介绍,现在举个简例,例名DynArr,见图8.1。
tstringdynarray用法
tstringdynarray用法tstringdynarray是一个Delphi编程语言中常用的数据类型,用于存储字符串的动态数组。
动态数组是一种可以根据需要自动调整长度的数组类型,可以灵活地存储和管理多个字符串。
使用tstringdynarray首先需要声明和初始化一个动态数组变量,类似于其他数据类型的声明。
例如:varmyArray: tstringdynarray;在声明变量后,可以使用SetLength函数为动态数组分配指定长度的存储空间。
例如,为myArray分配5个元素的存储空间:SetLength(myArray, 5);在动态数组中,可以使用索引访问和修改特定位置的字符串元素。
索引从0开始,表示数组中的第一个元素。
例如,访问和修改myArray的第三个元素:myArray[2] := 'Hello World'; //设置第三个元素的值为'Hello World'ShowMessage(myArray[2]); //显示第三个元素的值动态数组还可以通过添加和删除元素来动态调整其长度。
使用Length函数可以获取数组的当前长度。
例如,在数组末尾添加一个字符串元素:SetLength(myArray, Length(myArray) + 1); //增加一个元素的存储空间myArray[Length(myArray) - 1] := 'New Element'; //设置新添加的元素的值为'New Element'需要注意的是,当删除元素时,必须手动调整数组的长度。
例如,删除第一个元素:for i := 1 to Length(myArray) - 1 domyArray[i - 1] := myArray[i];SetLength(myArray, Length(myArray) - 1); //减少一个元素的存储空间通过合理使用tstringdynarray,可以方便地存储和操作多个字符串,实现更灵活的编程功能。
Delphi泛型动态数组的扩展.武稀松(wr960204)的博客
. wr960204
Delphi
.
2013 6 4 admin
Delphi
, –TArray.
,
. XE4
Helper , StringHelper, TArrayHelper Helper .
record,
Delphi . .
var // a, b, c: TArrayEx<Integer>; f: TArrayEx<Single>; s : TArrayEx<string>; // i: Integer;
class operator Explicit(Value: TArrayEx<T>): TArray<T>; overload;
class operator Explicit(Value: array of T): TArrayEx<T>; overload;
class operator Add(A, B: TArrayEx<T>): TArrayEx<T>; overload;
function Insert(AIndex: NativeInt; const Values: TArray<T>) : NativeInt; overload;
function Insert(AIndex: NativeInt; const Values: TArrayEx<T>) : NativeInt; overload;
uses System.Generics.Defaults, System.SysUtils; type
TArrayEx<T> = record strict private type
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Delphi之动态数组使用总结传统的Pascal 语言其数组大小是预先确定的,当你用数组结构声明数据类型时,你必须指定数组元素的个数。
专业程序员也许知道些许动态数组的实现技术,一般是采用指针,用手工分配并释放所需的内存。
Delphi 4中增加了非常简单的动态数组实现方法,实现过程效仿我前面讲过的动态长字符串。
与长字符串一样,动态数组的内存动态分配并且引用记数,不过动态数组不支持copy-on-write 技术。
这不是个大问题,因为你可以把变量值设置为nil释放数组内存。
这样你就可以声明一个不指定元素个数的数组,并用SetLength 过程给数组分配一个特定大小的内存,SetLength 过程还可以改变数组大小而不影响其内容,除此外还有一些字符串过程也可用于数组,如Copy 函数。
以下摘录的代码突出了一点,这就是:定义数组后必须先为它分配内存,然后才能开始使用:procedure TForm1.Button1Click(Sender: TObject);var Array1: array of Integer;begin Array1 [1] := 100; // error SetLength (Array1, 100); Array1 [99] := 100; // OK ...end;如果你只定义一个数组元素个数,那么索引总是从0开始。
Pascal 中的普通数组既能用不为零的下标,也能用非整数的下标,但动态数组均不支持这两种下标。
象普通数组一样,你可以通过Length、High和Low 函数了解到动态数组的状况,不过对于动态数组,Low 函数返回值总是0,High函数返回数组大小减1,这意味着空的动态数组其函数High返回值是-1,这是一个很怪的值,因为它比Low的返回值还小。
图8.1:例DynArr 窗体以上作了简短的介绍,现在举个简例,例名DynArr ,见图8.1。
例子实在是很简单,其实动态数组没有什么特别复杂地方。
我想通过该例说明几个程序员可能犯的错误。
程序中声明了两个全程数组并在OnCreate 事件中初始化了第一个数组:var Array1, Array2: array of Integer;procedure TForm1.FormCreate(Sender: TObject);begin // allocate SetLength (Array1, 100);end;这样就把数组所有值设置为0。
完成这段代码你马上就能读写数组元素的值,而不用害怕内存出错,当然条件是你没有试图访问超过数组上界的元素。
为了更好地初始化,程序中添加了一个按钮,执行数组元素赋值操作:procedure TForm1.btnFillClick(Sender: TObject);var I: Integer;begin for I := Low (Array1) to High (Array1) do Array1 [I] := I;end;Grow 按钮用于修改数组大小,但并不影响数组内容。
单击Grow 按钮后,你可以用Get value 按钮进行检验:procedure TForm1.btnGrowClick(Sender: TObject);begin // grow keeping existing values SetLength (Array1, 200);end;procedure TForm1.btnGetClick(Sender: TObject);begin // extract Caption := IntToStr (Array1 [99]);end;Alias 按钮的OnClick 事件代码稍复杂些,程序通过:= 算子把一个数组拷贝给另一个数组,从而有效地创建了一个别名(一个新变量,但引用内存中同一数组)。
从中可见,如果你改变了其中一个数组,那么另一个同样也会改变,因为它们指向同一个内存区:procedure TForm1.btnAliasClick(Sender: TObject);begin // alias Array2 := Array1; // change one (both change) Array2 [99] := 1000; // show the other Caption := IntToStr (Array1 [99]);在btnAliasClick 事件中增加了两部分操作内容。
第一部分是数组等同测试,不过并不是测试实际的数组元素,而是测试数组所引用的内存区,检测变量是不是内存中同一数组的两个别名:procedure TForm1.btnAliasClick(Sender: TObject);begin ... if Array1 = Array2 then Beep; // truncate first array Array1 := Copy (Array2, 0, 10);end;btnAliasClick 事件的第二部分内容是调用Copy 函数。
该函数不仅把数据从一个数组移到另一个数组,而且用函数创建的新数组取代第一个数组,结果变量Array1 所引用的是11个元素的数组,因此,按Get value 和Set value 按钮将产生一个内存错误,并且触发一个异常(除非你把范围检查range-checking 选项关掉,这种情况下,错误仍在但屏幕上不会显示异常)。
虽然如此,Fill 按钮仍能正常工作,因为需要修改的数组元素由数组当前的下标范围确定。
自从有了动态数组,链表除了在教科书里出现外,已经很少在实际编程中被使用了,事实也是如此,数组的确比传统链表快得多,而且也方便的多。
从Delphi4起,开始了内建各种类型的动态数组支持。
但是,对我们来说动态数组支持似乎做的不够彻底,因为Delphi竟然连删除、插入、移动连续元素的函数都没有提供,让人使用起来总觉得不够爽!!!J 。
作为一名程序员,我们当然要有自己解决问题的能力,下面就让我们简单介绍一下Delphi 下的动态数组。
在Delphi中,数组类型有静态数组(a : array[0..1024] of integer)、动态数组(var a : array of integer)、指针数组(即指向静态数组的指针)和开放数组(仅用于参数传递)。
静态数组、指针数组有速度快的好处,动态数组有大小可变的优势,权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。
动态数组声明之后,只有下面几个函数可┎僮鳎?o:p>1.设置数组大小,可以任意缩减或增加数组大小Procedure SetLength(var S ; NewLength : integer);2.取出连续元素,复制给另一个数组变量Function Copy(s;Index,Count : integer) : array ;3.取得数组大小及上下限Function Length(s):integer;Function High(x):integer;Function Low(x):integer;值得注意的是,不加const或var修饰的动态数组会被作为形参传递,而动态数组用const 修饰并不意味着你不能修改数组里的元素(不信你可以字自己在程序中试试。
还有一点是High函数调用了Length 函数,所以我们在获取数组上限时最好直接用Length(s) 函数。
动态数组在内存空间中占用4个字节. 动态数组在内存中的分配表如下:偏移量内容-8 32-bit 引用计数-4 32-bit 数组长度0..数组长度* (元素尺寸) - 1 数组元素元素尺寸=Sizeof(元素类型)根据上面的分配情况,可以得到如下结果:如果我们想要清空一个动态数组只需要把“数组长度”和“引用计数”清空即可。
”引用上面的一句话就是:“权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。
”下面是清空动态数组的函数:procedure DynArraySetZero(var A);varP: PLongint; //占用4个字节,正好符合32 位内存排列beginP := PLongint(A); // 指向A的地址Dec(P); //P地址偏移量是sizeof(A),指向了数组长度P^ := 0; // 长度清空Dec(P); // 指向引用计数P^ := 0; //计数清空。
end;上面的函数就这么简单,而且效率也非常高。
下面让我们再来看看怎样删除动态数组中的元素,函数体如下:{************************************A变量类型,elSize = SizeOf(A)index 开始删除的位置索引,Count 删除的数量****************************************}procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);varlen, MaxDelete: Integer;P : PLongint; //4 个字节的长整形指针beginP := PLongint(A);// 取的A的地址if P = nil thenExit;{下面这句完全等同于Dec(P) ; len := P^ 因为Dec(P) = Pchar(P) – 4 同样是移动4 字节的偏移量,只不过后者按字节来移动}len := PLongint(PChar(P) - 4)^; // 变量的长度,偏移量-4if index >= len then //要删除的位置超出范围,退出Exit;MaxDelete := len - index; // 最多删除的数量Count := Min(Count, MaxDelete); // 取得一个较小值if Count = 0 then // 不要求删除Exit;Dec(len, Count);// 移动到要删除的位置MoveMemory(PChar(P)+index*elSize , PChar(P)+(index + Count)*elSize , (len-index)*elSize); //移动内存Dec(P); //移出“数组长度”位置Dec(P); //移出“引用计数”位置//重新再分配调整内存,len 新的长度. Sizeof(Longint) * 2 = 2*Dec(P)ReallocMem(P, len * elSize + Sizeof(Longint) * 2);Inc(P); // 指向数组长度P^ := len; // new lengthInc(P); // 指向数组元素,开始的位置PLongint(A) := P;end;对上面的例子,我们需要注意的是elSize 参数,它必须是SizeOf(DyArray_Name),表示元素所占用的字节数。