Object Pascal語言

   Object Pascal語言

  控制串由一個或多個控制字符組成,由“#”開頭,後面緊跟一個範圍在0~255的無符號的整數,用於代表相應的ASCII字符。
  下面再列出一些變量聲明的例子:
var X, Y, Z: Double;
I, J, K: Integer;
Digit: 0..9
C: Color;
Done, Error: Boolean;
Operator: (Plus, Minus, Times);
Hue1, Hue2: set of Color;
Today: Date;
Results: MeasureList;
P1, P2: Person;
Matrix: array[1..10, 1..10] of Double;
  在聲明變量時,還可以帶一個可選的Absolute子句,用於指定變量的值在內存中存儲的絕對位置,
 例如:
var CrtMode:Byte Absolute $0040:$0049
  上例中,聲明瞭一個Byte類型的變量CrtMode,Absolute指示字後第一常量是段的值,第二個常量是偏移量。變量可以在定義時就指定一個初值。
  例如:
var I: Integer = 7;
  等價於:
var I: Integer; ...I := 7;
  指定的初值可以是任何變量類型的常數表達式。
1.純常量
  純常量是一種預先定義的標識符,其值在定義後永遠不會改變。
  例如:const MaxValue = 237;
2.類型常量
  與純常量不同,類型常量用於保存數組、記錄、過程以及指針等類型的值。類型常量不能出現在常量表達式中。
  在缺省的編譯器狀態(即{$J+})下,類型常量的值可以改變,這時類型常量更像初始化過的變量。但當編譯器狀態改爲{$J-}時,則類型常量的值在運行期就無法改變,此時,類型常量實際上變成了只讀變量。
  聲明類型常量的語法規則爲:
  const identifier: type = value
  這裏,常量名要符合 Pascal語言關於標識符的規則。type是除了文件型和可變型之外的所有類型。Value是一個類型爲type的表達式。例如:
  const Max: Integer = 100;
  一般來說,Value爲一個常量表達式,但當type是數組、記錄、過程和指針時,必須執行特殊的規則。
6.3 數 據 類 型
  類型是某類數據的名稱,用於確定能存儲信息,及能存儲多少信息等。ObjectPascal是一種強類型的語言,其數據類型的定義、聲明以及數據的賦值和傳遞都必須遵循嚴格的語法規則。因此,學習和掌握數據類型是設計好程序的關鍵。
  Pascal支持豐富的數據類型,本書將其分爲6大類:
?簡單類型,包括有序類型和實數型。其中有序類型是指整數類型、字符類型、布爾類型、枚舉類型以及子界類型。
?字符串類型。?結構類型,包括集合類型、數組類型、記錄類型、文件類型、類類型、類引用類型、接口類型等。
?指針類型。
?過程類型。
?變體類型。
6.3.1 簡單類型
  Object Pascal的簡單類型包括有序類型和實數型。其中有序類型是指整數類型、字符類型、布爾類型、枚舉類型以及子界類型。
  下面分別進行討論。
  1.有序類型
  有序類型是指整數類型、字符類型、布爾類型、枚舉類型以及子界類型。有序類型是一個有序數的集合。在每一種有序類型中,任何一個該類型的元素都有一個唯一的先行數(第一個除外)和唯一的後繼數(最後一個除外)。而且。每個值均有一個確定的序號。對整型數而言,該序號就是該整數的本身。而其它的有序類型(子界類型除外),第一個值的序號是0,第二個是1,依此類推。如果某個有序類型的值爲N,則其先行數爲N-1,後繼數爲N+1。
  Object Pascal預先定義了一些函數,專門用於處理有序類型的表達式和變量,表6-1列出了最常用的幾個。
  表6-1 常用函數
函數  參數     返回值             備註
Ord  有序類型表達式 有序類型表達式值的序號  不能帶Int64參數
Pred 有序類型表達式 有序類型表達式值的先行數 不能在擁有Write過程的
                         特性上使用
Succ 有序類型表達式 有序類型表達式值的後繼數 不能在擁有Write過程的特性上使用
High 有序類型標識符或變量 該類型中序號最大的值 也可在short-string類型或數組
Low 有序類型標識符或變量 該類型中序號最小的值也可在short-string類型或數組
  例如,表達式 High(Byte)將返回255,這是因爲Byte類型的序數最大爲255。表達式Succ(2) 將返回3,這是因爲 3緊跟在2的後面。標準過程Inc和Dec用於增加或減少一個有序類型變量的值,例如:Inc(I)等價於執行 I := Succ(I)如果I是一個整數類型,還等價於執行: I := I + 1
 下面分別對整數類型、字符類型、布爾類型、枚舉類型以及子界類型進行介紹: (1)整數類型(Integer)在Object Pascal中,Integer類型是所有有符號整數的統稱。
  實際上,整數類型可以分爲基本整數類型(Fundamental type)和一般整數類型(generic type)。一般整數類型(generic type)包括Integer和Cardinal兩種。在實際編程時,請儘量區分這兩種,因爲底層CPU和操作系統對結果進行了優化。
  表6-2列出了Integer和Cardinal的取值範圍及存儲格式。
  表6-2 一般整數類型的取值範圍及存儲格式
數據類型  取值範圍        存儲格式
Integer  ?147483648..2147483647  32位有符號
Cardina  l0..4294967295      32位無符號
  基本整數類型包括Shortint、Smallint、Longint、Int64、Byte、Word和Longword。表6-3列出了它們的取值範圍及存儲格式。
  表6-3 基本整數類型的取值範圍及存儲格式
數據類型  取值範圍     存儲格式
Shortint  -128..127    signed 8-bit
Smallint  -12768..32767  signed 16-bit
Longint   -2147483648..2147483647 signed 32-bit
Int64    -2^63..2^63?   signed 64-bit
Byte    0..255      unsigned 8-bit
Word    0..65535     unsigned 16-bit
Longword  0..4294967295  unsigned 32-bit
  一般整數類型的實際範圍和存儲格式隨着Object Pascal的不同實現而不同,但通常根據當前CPU和操作系統來採取最佳的操作方式。
  一般整數類型是最常用的整數類型,可以充分利用CPU和操作系統的特性,因此程序中應當儘量使用一般整數類型。基本整數類型獨立於操作系統和CPU,只有當應用程序的數據範圍或存儲格式特別需要時,才使用基本整數類型。
  通常情況下,整數的算術運算結果爲Integer類型,等價於32位的Longint類型。只有當操作數存在 Int64類型時,才返回Int64類型的值。因此,下面的代碼將產生錯誤的結果:
var I: Integer; J: Int64;
 ...
I := High(Integer);
J := I + 1;
  在這種情況下,要取得一個Int64的值,必須進行類型轉換:
J := Int64(I) + 1;
  注意:絕大多數例程在遇到Int64時都把它轉換爲32位。但例程High,Low,Succ,Pred,Inc,Dec,IntToStr和IntToHex則完全支持Int64參數。Round,Trunc,StrToInt64,和StrToInt64Def函數可以返回Int64類型的結果。
(2)字符類型(Char)
  字符類型中Char類型設計來只存儲一個字符。一個字符佔一個字節,因此Char數據類型可以存儲256個不同的字符,其對應的整數爲0到255。
  除了Char數據類型外,Delphi還提供了Char類型的擴展,即AnsiChar和WideChar型。表6-4是字符數據類型的列表。
  表6-4 字符整數類型
字符類型  佔用字節數  存儲內容
AnsiChar   1      存儲一個Ansi字符。
WideChar   2      存儲一個UniCode字符。
Char     1      目前,對應AnsiChar。但Delphi將來的版本可能對應於WideChar。
  Ansi字符集是擴展的ASCII字符集,仍然佔一個字節。目前,Char對應AnsiChar,但Borland公司在將來的Delphi版本中可能使Char對應WideChar。  
 WideChar用來支持泛字符集(Unicode)。Unicode字符佔用兩個字節,可以有65536種不同的取值,可以表達現代計算機中使用的世界上所有的字符,包括圖形符號和用於出版業的特殊符號等。
  UniCode字符集的前256個字符對應着ANSI字符。如果你把一個AnsiChar字符放到WideChar字符類型的變量中,WideChar字符類型變量的高字節將全部置爲0,AnsiChar字符存放到WideChar字符類型的變量的低字節中。
 注意:Windows NT全面支持Unicode字符號集,但Windows 95卻不同。如果你希望書寫的程序同時能在兩種系統上運行,必須使用SizeOf()函數,以確定字符佔多少字節。
(3)布爾類型(Boolean)
  Boolean數據類型的變量只存儲一個邏輯值,例如True或False。共有4種Boolean數據類型,見表6-5。
表6-5 布爾類型
類型  說明
Boolean 佔1個字節
ByteBool 佔1個字節
WordBool 佔2個字節
LongBool 佔4個字節
  Delphi提供多種Boolean數據類型的目的是爲了兼容,因爲在某些情況下,Windows需要用一個字(2個字節)或雙字(4個字節)來表示一個布爾值。
(4)枚舉型
  所謂枚舉類型,就是用一組數量有限的標識符來表示一組連續的整數常數,在類型定義時就列出該類型可能具有的值。枚舉類型是一種用戶自定義的簡單數據類型。在類型定義時就列出該類型可能具有的值。下面是枚舉類型定義的一些例子:type
  TDays=(Monday,YuesDay,Wednesday,Thursday,Friday,Saturday,Sunday);
TPrimaryColor=(Red,Yelloow,Blue); TDepartment=(Finance,Personnel,Engineering,Marketing,MIS); TDog=(Poodle,GoldenRetriever,Dachshund,NorwegianElkhound,Beagle);
  枚舉類型定義中的每個值都對應一個整數,整數值由該值在類型定義表中的位置決定,通常類型定義的第一個數對應的整數值爲0。例如,在TDay類型定義中Monday對應值爲0、Tuesday值爲1,等等。如果你把DayOfWeek定義爲Integer,通過賦整數值來代表星期幾,也可以得到同樣的結果。但是,由於枚舉類型表達的意思明確、直觀、便於記憶,因此使用枚舉類型仍有必要。
  下面是聲明一個枚舉類型的語法(圖6.2)。
  其中標識符列表中的標識符之間用逗號隔開,它列出該類型可能具有的值。
下面是聲明一個枚舉類型變量的舉例:
  var DayOfWeek:TDays;
  Hue:TPrimaryColor;
  Department:TDepartment;
  Dogbreed:TDog;
  也可以把類型聲明和變量聲明合二爲一,例如:
var DayOfWeek:(Monday,YuesDay,Wednesday,Thursday,Friday,Saturday,Sunday);
  在聲明枚舉類型和枚舉變量時,請注意以下幾點:
1)枚舉的元素只能是標識符,標識符的命名必須符合 Pascal關於標識符的規定,例如下面的聲明就是錯誤的:
type TDays=(0,1,2,3,4,5,6,7);
2)同一個枚舉元素不能出現在多個枚舉類型中。例如下面的聲明就是錯誤的:
type TColors1=(Red,Blue,Green,White,Black);
   TColors2=(Yellow,Lime,Silver,Green);
 兩個類型變量中都有Green元素,是不允許的。
3)不能直接用枚舉類型中的元素參加運算,例如,下面的語句就是錯誤的:
X:=Red+Blue;
  但是,可以用某個枚舉類型中的元素對枚舉變量賦值,例如,下面的語句:
DayOfWeek:=Monday;
(5)子界型
  子界類型是Integer,Boolean,Char及枚舉型等稱爲宿主類型數據的一個子集。當你要限制一個變量的數據範圍時,使用子界類型就特別有用。子界類型也是一種用戶自定義的簡單數據類型。要定義子界類型,必須說明區間的最大值和最小值,下面是子界類型定義的一些例子:
type TCompassRange = 0..360;
TValidLetter ='A'..'F'
TMonthlyIncome=10000..30000;
THours =0..23; TPrecipitation=(Drizzle,Showers,Rain,Downpour,Thunderstorm); {枚舉型}
TRain =Drizzle..Downpour; {上面枚舉型的子界型}
  下面是聲明一個子界類型的語法規則(圖6.3)。
  其中兩個常數(稱爲上界和下界)必須是同一種有序類型,如Integer,Boolean,Char及枚舉型等,但不能是Real數據類型。第一個常數必須小於或等於第二個常數。
  下面是聲明子界類型變量的舉例:
var Compass:TCompassRange;
ValidChar:TValidLetter;
  在聲明子界類型和子界類型變量時,請注意以下幾點:
1)上界常數和下界常數必須是同一類型,且都是有序類型。
2)子界類型變量具有宿主類型數據的所有運算特性,但運算的結果必須在範圍內。
3)上界常數和下界常數可以是表達式。例如:
const X = 10; Y = 50;
type Color = (Red, Green, Blue);
Scale = X * 2..X * 20;
2.實數類型(Real)
  實數類型是帶有小數部分的數值,存儲實數。有6種不同的Real數據類型,它們在範圍、精確度、大小等方面都不相同。見表6-6。
  實數類型
數據類型 取值範圍           有效位 存儲字節
Real48  2.9 x 10^-39 .. 1.7 x 10^38  11..12 6
Single  1.5 x 10^-35 .. 3.4 x 10^38  7..8  4
Double  5.0 x 10^-324 .. 1.7 x 10^308 15..16 8
Extended 3.6 x 10^-4951 .. 1.1 x 10^4932 19..20 10
Comp   -2^63+1 .. 2^63 ?        19..20 8
Currency 22337203685477.5808..922337203685477.5807 19..20 8
當前通常使用的Real等價與Double。
6.3.2 字符串類型
  Delphi在處理字符串時,提供了多種方式,表6-7是Delphi使用的字符串類型。
表6-7 字符串類型
類型    最大長度  存儲的字符  是否以Null結尾
ShortString 255個字符 AnsiChar   否
AnsiString~ 2^31個字符 AnsiChar   是
String   或者255或者~2^31個字符 ANSIChar都可能
WideString ~2^30個字符 WideChar   是
  從上表可知,Delphi主要支持兩種類型的字符串: ShortString和AnsiString。WideString類似於AnsiString,只是其存儲的字符爲WideChar。
  ShortString數據類型定義的是長度在1到255之間動態長度字符串。像數組一樣,單個字符可以通過引用它們的索引進行存取。位於0的字節存儲了代表字符串當前所賦值長度的數值(只能通過關閉範圍檢查才能訪問)。ShortString數據類型主要是爲了能和Delphi 1.0和Borland Pascal的早期版本兼容。
  AnsiString(又稱爲long String或huge String)數據類型的定義是動態分配的,長度幾乎可以無限的(僅受可用內存限制)以NULL結尾的字符串。AnsiString中的字符由AnsiChar數據類型的字符組成。
  建議最好使用AnsiString數據類型。這是因爲AnsiString數據類型的變量是動態分配的,當把一個更長的字符串放入AnsiString數據類型的變量時,Delphi會從新爲該變量申請空間。如果要顯式地改變字符串的長度,可以使用SetLength() 函數來分配一塊恰當的內存;使用AnsiString數據類型的另外一個優點是,AnsiString字符串是以NULL結尾,即在最後一個字符之後自動加上一個NULL字符表示字符串結束,與操作系統的大多數函數例程兼容,例如Win32 API,從而在調用操作系統函數例程時更加方便,不需要使用StrPCopy()來將以Pascal風格的字符串轉換爲以NULL結尾的字符串。Delphi VCL構件的所有特性、事件使用AnsiString來傳遞參數,以簡化、統一VCL和API之間的接口。
  String既可以是SHortString類型也可以是AnsiString類型,缺省是AnsiString類型。例如,如果你像下面那樣定義字符串:
var S: String;// S is an AnsiString
  則編譯器假定你要創建一個AnsiString數據類型變量。
  使用$H編譯命令可以改變缺省定義。當在程序中把編譯開關$H的狀態改爲{H-}時,String缺省是ShortString類型;當在程序中把編譯開關$H的狀態改爲{H+}時,String缺省是AnsiString類型。例如:
var {$H-} S1: String; // S1 is a ShortString
{$H+}
S2: String; // S2 is an AnsiString
  如果定義中指明瞭長度(最大爲25 5),則String爲ShortString。例如:
var S: String[63]; // S是一個 長度爲63的ShortString變量。
6.3.3 結構數據類型
  結構類型在內存中存儲一組相關的數據項,而不是像簡單數據類型那樣單一的數值。Object Pascal結構類型包括集合類型、數組類型、記錄類型、文件類型、類類型、類引用類型、接口類型等。這裏,我們只介紹集合類型、數組類型、記錄類型和文件類型。類類型、類引用類型和接口類型放在下一章介紹。
1.數組(Array)
  數組是一種數據類型數據的有序集合,是代表一定數量具有相同類型變量的一種數據類型。Object Pascal數組可與任何簡單數據類型或字符串類型等一起使用。數組可用於聲明一個簡單變量或作爲一個記錄類型定義的組成部分。
  (1)數組的定義
  下面是聲明一個數組類型的語法規則(圖6.4)。
 要聲明一個數組變量,要求你提供一個標識符,使用array保留詞,在方括號中指定數組的界限,並指定編譯器數組將用於存儲什麼類型,例如:
Var Check:array[1..100] of Integer;
 範圍標點‘..’用於表示Check是一個有100個整數的數組,這些整數從1到100編號。範圍編號是一個子界類型,可以是0,也可以是正數或負數,或者字符,或其它有序類型。
  下面是聲明數組類型及數組類型變量的舉例:
Type TCheck = array [1..100] of Integer;
Var CheckingAccount:TCheck;
  上面是先定義數組類型,然後定義數組變量。其實上,也可以同時定義類型、變量,例如:
var Kelvin:array[0..1000] of Temperatures;
TwentiethCentury: array[1901..2000] of Events;
LessThanzeroo: array[-999..-400] of Shortint;
DigiTValues:array ['0'..'9' of Byte;
SecretCode:array[''A'..'Z' of char;
 訪問數組中的元素很簡單,只要在標識符後面的方括號中給出指定的元素的索引號即可。例如:
Check[5]:=12;
J:=9;
Check[J]:=24;
  要訪問數組中的所有元素,可以使用循環語句。例如 :
For J:=1 to 10 do Check[J]:=0;
(2)多維數組
  上面介紹的是一維數組。實際上,數組可以是多維的。例如,如果你想編寫一個數組來容納一張電子表格中的值,那麼就可以使用2維數組。下面的例子說明如何使用2維數組定義一個有20行和20列的表格:
Type Ttable = array[1..20,1..20] of Double;
Var BigTable:Ttable;
  要將2維數組中的所有數據初始化,可以使用如下語句:
Var Col,Row:Intger;
.
.
.
for Col:=1 to 20 do
  for Row:=1 to 20 do
   BigTable[Col,Row]:=0.0;
  使用多維數組時,要記住的一件事是數組爲每維所佔據的RAM數都呈冪級數增加。例如:
Aline:Array[1..10] of byte;佔用10個字節
AnArea:Array[1..10,1..10] of byte;佔用10*10=100個字節
Avloume:Array[1..10,1..10,1..10] of byte;佔用10*10*10=1000個字節
(3)字符數組
  前面介紹的字符串,實際上就是一個1維字符數組,只不過Pascal對字符串類型作了特殊的准許,你可以把它看作一個整體。字符串類型本質上等同於下列類型:type StringType:array[0..255] of char;但是,雖然你可以把一個字符串看待,但它仍然保持其數組的特性。例如在定義一個字符串類型變量時,你可以說明字符串的大小,就像你定義字符數組的大小一樣。下面是幾個字符串類型定義:
type MyString:string[15];
BigString:string;
LittleString:string[1];
 上面語句定義MyString類型包含15個字符,LittleString包含1個字符,BigString沒有說明大小,就取字符串包含字符的最大個數255。然後你可以定義這些類型的變量,就像使用其它類型一樣:
Var MyName:MyString;
Letter,Digit:LittleString;
  你可以對字符串變量進行賦值: MyName:='Frank P.BorLand';
 ?因爲MyName長度爲15,因此只能容納15個字符。如果執行下面語句: MyName:=Frank P.Borland?則MyName變量中只存有FranK.P.Borlan其餘部分被捨棄。
 爲了取得字符串中的一個字符,可以按如下方法進行:AChar:=MyName[2];
 但是,如果索引大於字符串變量的長度,則結果不可知。例如: AChar:=MyName[16];則AChar將被設置爲某個不確定的字符,換句話說,就是廢字符。
  在字符串類型的數組中,字符串的第一個位置[0]包含有字符串的長度,因此數組的實際長度比該字符串長度大1個字節。你可以使用Length函數或下面的代碼來得到一個字符串的長度:L:=Ord(String[0]);
(4)數組類型常量
  數組類型常量的每個字段都是類型常量,下面是聲明數組類型常量的語法規則(圖6.5)。
  從圖中可以知道,一個數組類型常量由括號括起來的類型常量組成,不同類型常量用逗號隔開。
  像簡單類型常量一樣,數組類型常量用來定義一個數組常量,下面是一個例子。
type TStatus = (Active, Passive, Waiting);
TStatusMap = array[TStatus] of string;
const StatStr: TStatusMap = ('Active', 'Passive', 'Waiting');
  上面的例子首先定義一個數組TStatusMAp,然後定義一個數組常量StatStr。該數組常量的目的是把TStatus類型的值轉化爲對應的字符串。下面是數組常量StatStr元素的值:
StatStr[Active] = 'Active'StatStr[Passive] = 'Passive'
StatStr[Waiting] = 'Waiting'
  數組常量的元素類型可以是除文件類型以外的任何類型。字符數組類型常量既可以是字符也可以是字符串,例如:
 const Digits: array[0..9] of Char = ('0', '1', '2', '3', '4', '5','6', '7', '8', '9');
 該數組常量也可以表示爲:const Digits: array[0..9] of Char = '0123456789';
  初始化字符數組類型常量的字符串長度可以小於數組類型的定義長度,例如:var FileName: array[0..79] of Char = 'TEST.PAS';這時數組餘下的字符空間自定置NULL(#0),因此數組也變成了一個以NULL結尾的字符串。
  多維數組類型常量的定義採用括號的形式,每一維用括號括起,不同維及不同元素常量之間用逗號隔開。最裏面的常量對應最右面的維數。
  例如:type TCube = array[0..1, 0..1, 0..1] of Integer;const Maze: TCube = (((0, 1), (2, 3)), ((4, 5), (6, 7)));
 Maze常量數組各元素的值爲:
Maze[0, 0, 0] = 0
Maze[0, 0, 1] = 1
Maze[0, 1, 0] = 2
Maze[0, 1, 1] = 3
Maze[1, 0, 0] = 4
Maze[1, 0, 1] = 5
Maze[1, 1, 0] = 6
Maze[1, 1, 1] = 7
(5)開放式數組
  所謂開放式數組,是指數組作爲形參傳遞給過程或函數時其長度是可變的,這樣在調用過程或函數時,可以傳遞不同長度的數組作爲實際參數。
  開放式數組在過程或函數中作爲形參可以定義爲: array of T這裏T是數組的元素類型標識符,實際參數必須是T類型的變量或元素類型爲T的數組變量。在過程或函數內形參的作用可看作爲下面的數組: array[0..N - 1] of T
  這裏N是實參中元素的個數。實際上實參的上下界被映射到0到 N-1。如果實參是類型T的簡單變量,則它被看成爲只有類型T元素的數組。
   開放數組只能以開放數組參數或一個未定義變量參數的的形式傳遞到過程或函數。開放數組可以作爲數值參數、常數參數或變量參數,並與這些參數具有同樣的語法規則。作爲形式參數的開放數組不允許整體賦值,只能訪問它的元素。並且對元素的賦值不影響實參。
 當開放式數組作爲數值參數時,編譯器將在內存中開闢一塊區域存放實參的拷貝,等過程或函數退出後再釋放這塊區域,這樣當實參是個很大的數組時,可能會發生棧溢出的問題。在使用開放數組參數時,可以使用Low函數獲得當前最小下標(不過總是爲0),使用High函數獲得當前最大下標,使用SizeOF函數獲得當前數組大小。下面是一個例子,演示了開放式數組的使用。
{定義兩個長度不同的數組變量}
Var X1:array[1..10] of Double;
X2:array[1..30] of Double;
  {Clear過程對一個Double數組的各元素清0,SUM過程計算一個Double數組的各元素之和。兩個過程的參數都是開放式數組。}
procedure Clear(var A: array of Double);
  var I: Integer;
begin
  for I := 0 to High(A) do
   A[I] := 0;
end;
function Sum(const A: array of Double): Double;
  var I: Integer; S: Double;
begin
 S := 0;
 for I := 0 to High(A) do S := S + A[I];
 Sum := S;
end;
begin
 Clear(X1);
 Clear(X2);
 Sum(X1);
 Sum(X2);
end;
  當開放式數組的元素類型爲Char時,實參可以是一個字符串常數。例如:
procedure PrintStr(const S: array of Char);
  var I: Integer;
begin
  for I := 0 to High(S) do
   if S[I] <> #0 then Write(S[I])
   else Break;
end;
  下面是合法的過程調用語句:
  PrintStr('Hello world');
  PrintStr('A');
(6)動態數組
  在Delphi中,除了定義靜態數組外,還可以定義動態數組。動態數組只需說明數組的類型信息(包括數組的維數和數組元數的類型),但不需要定義元素的個數。例如:
A: array[1..100] of string;//靜態數組
B: array of integer//動態數組
C: array of array of string;//動態數組
  這裏A是靜態數組,B是一維的整數動態數組,C是二維的字符串動態數組。
  動態數組沒有固定的長度。相反,當爲動態數組賦值或使用SetLength過程時,動態數組的內存空間將重新分配。動態數組的定義形式是:
  array of baseType
  例如: var MyFlexibleArray: array of Real;
  定義了一個類型爲實數型的一維動態數組。注意,聲明語句並沒有爲MyFlexibleArray分配內存。要爲動態數組分配內存,需要調用SetLength過程。例如:
  SetLength(MyFlexibleArray, 20);上面語句分配20個實數,標號從0到19。
  動態數組的標號是整數類型,標號總是從0開始。使用Length,High和Low函數可以取得有關動態數組的特性。Length函數返回數組中元素的個數。High函數返回數組的最大標號,Low返回0。
2.集合類型
  集合類型是Integer,Boolean,Char,枚舉型,子界型等類型數據的一個子集。在應用程序中,當要檢測一個數是否屬於一個特定的集合時,就可以使用集合類型。(1)集合類型的定義下面是聲明一個集合類型的語法規則(圖6.6)。
 其中Set of是保留字,ordinal Type是集合的基類型,可以是任何有序類型如整數型,布爾型,字符型,枚舉型和子界型,但不能是實型或其它自定義類型。下面是一些集合類型的例子:
type VoterDataSet= Set Of (Democrat,Republican,Male,Female, LowOpinion,HighOption,Confused);
Chars = Set of Char;
Letters = Set of 'a'..'z';
VIBGYOR= (Violet,Indigo,Blue,Green,Yellow,Orange,Red); {這是枚舉型}
ColorSet = set of VOBGYOR;{上面枚舉型的集合類型}
  一個集合類型的變量的值實際上是它的基類型的一個子集,可以爲空集。一個集合最多可有256個元素。因此下面的集合定義是錯誤的:
 type SET1= Set Of Integer;
  這是因爲Integer集合的元素個數遠遠大於256。
 下面是集合類型變量的一些例子:
var Voter: VoterDataSet;
Color: ColorSet;
Lets:Letters;
  Pascal使用方括號來表示集合,例如:
  [Democrat];表示只含Democrat的集合。
  一個集合可以擁有0個元素,這時稱之爲空集,用兩個方括號表示,其中什麼也沒有。對於集合類型變量,你可以進行+,-,=,*(並),IN等運算。見下表6-8。
表6-8 集合類型運算
操作符 描述            舉例
+   往一個集合中添加元素    Aset:=Aset+AnotherSet;
-   從一個集合中去除元素    Aset:=Aset-AnotherSet;
*   去除兩個集合中都沒有的元素 Aset:=Aset*AnotherSet;
In   測試元素          Bool:=AnElement in Aset
 下面是集合運算的例子:
Voter:=[HighOption];
Voter:=Voter+[Democrat];
Voter:=Voter+{male};
Voter:=Voter-[HighOption];
 If HighOption in Voter then SendtheVoterFlowers;
(2)集合類型
  常量像簡單類型常量一樣,集合類型常量用來定義一組常量的集合。例如:
type TDigits = set of 0..9;
TLetters = set of 'A'..'Z';
const EvenDigits: TDigits = [0, 2, 4, 6, 8];
Vowels: TLetters = ['A', 'E', 'I', 'O', 'U', 'Y'];
  上面的例子首先定義兩個集合類型TDigits和Tletters,然後定義了兩個集合常量,其中EvenDigits的值域是[0, 2, 4, 6, 8],它爲TDigits的一個子集;Vowels的值域是 ['A', 'E', 'I', 'O', 'U', 'Y'],它爲TLetters的一個子集。
3.記錄類型
  記錄是一系列相關的變量,這些變量被稱爲域,它們放在一起,作爲一個整體使用。例如,一個僱員可能包含姓名、僱用時間、薪金等數據,這時你可以像下面那樣定義一個僱員記錄類型:
type TEmployee = record LastName: String[20];
FirstName:String[15];
YearHired:1990..2000;
Salary:Double;
Position:string[20];
end;
  Pascal的記錄類型跟數據庫中的記錄很相似,記錄類型中的元素可以理解爲數據庫中的字段,事實上Pascal正是借用了數據庫中的記錄和字段的概念。
(1)記錄類型的定義
  下面是聲明記錄類型的語法規則
 記錄可以一個字段也沒有,即爲空記錄;一個記錄可以有一個固定部分(fixed part),在固定部分,每個字段都有其確定的標識符和數據類型,它們在內存中分別佔用不同的區域;一個記錄也可以加入一個可變部分(variantpart)。聲明記錄變量與聲明其它類型變量一樣,下面是兩個記錄變量的說明:
 var NewEmployee,PromotedEmployee:TEmployee;
 記錄類型中的每個域都有一種數據類型,你既可以單獨訪問這些域,也可以把記錄作爲一個整體來使用。例如,你可以像下面那樣訪問NewEmployee記錄中的Salary域或整個記錄:
NewEmployee.Salary:=43211.00;
PromotedEmployee:=NewEmployee;
  當你要訪問記錄內的域時,需要指定記錄名,並在記錄名後加(.),然後跟上域名。例如:
PromotedEmployee.Position
  如果要對多個域賦值,則每個域前都必須加記錄名。例如:
PromotedEmployee.LastName :='Gates'
PromotedEmployee.FirstName:='Bill'
PromotedEmployee.YearHired:=1990;
PromotedEmployee.Salary:=92339.00;
PromotedEmployee.Position:='Manager'
 ?Pascal提供了With語句,使你可以減少重複書寫記錄名的煩惱。With語句的語法是: With記錄變量名Do ...
  每個可變部分由至少由一個常量(Constant)標識,所有常量必須是唯一的,並且類型爲與tag field type指定類型相容的類型。Identifier用於記錄可變部分的可選部分,稱爲識別字段標識符。如果定義了識別字段標識符,程序可以使用該標識符決定在給定的時間內哪個可變部分是活動的,如果沒有定義識別字段標識符,程序必須根據其它規則選定記錄可變部分。
  下面是帶有可變部分的記錄類型的例子:
type TPolygon = record X, Y: Real;
case Kind: Figure of
  TRectangle: (Height, Width: Real);
  TTriangle: (Side1, Side2, Angle: Real);
  TCircle: (Radius: Real);
End;
 注意:記錄可變部分的字段不能是長字符串類型和變體類型,也不能含有長字符串類型和變體類型分量的構造類型。
(2)記錄類型常量
  記錄常量的每個字段都是類型常量,
  一個記錄類型常量每個字段由一個標識符和類型常量組成,不同字段用分號隔開,字段部分用括號括起。像簡單類型常量一樣,記錄類型常量用來定義一個記錄常量,下面是一些例子。
type TMonth = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
TDate = record D: 1..31;
M: Month;
Y: 1900..1999;
end;
const
  SomeDay: TDate = (D: 2; M: Dec; Y: 1960);
  上面的例子首先定義一個記錄類型TDate,然後定義了一個記錄常量SomeDay。注意:記錄類型常量中個字段的出現順序必須與記錄類型定義中的順序一致。如果記錄類型包括文件類型字段,則不能定義該記錄的記錄常量。如果記錄類型包括可變部分,則只有被選擇的可變部分可以定義常量。
4.文件類型
  文件是指相同類型元素的有序集合。Delphi處理文件有三種方式,一種是使用Object Pascal標準的文件處理技術;一種是使用Windows的文件處理函數;還有一種是使用文件流對象。
  Object Pascal標準的文件處理技術,有專門的數據類型和文件處理例程,並且與Windows的標準API不兼容,但對於熟悉Pascal的用戶來說,仍然是操作文件的好選擇。下面我們就對此進行介紹。
  聲明一個文件類型的語法如下: type fileTypeName = file of type
  這裏,fileTypeName是任何有效的標識符, type是一種大小固定的數據類型,稱之爲基類型。 基類型不能使用指針類型,不能包括動態數組、長字符串、類、對象、指針、可變類型以及其它文件類型。但可以是其它結構類型,例如:
type
PhoneEntry = record FirstName, LastName: string[20];
PhoneNumber: string[15];
Listed: Boolean;
end;
PhoneList = file of PhoneEntry;
  這裏,PhoneEntry是自定義的結構類型,PhoneList是以PhoneEntry爲基類型的文件類型。在定義了文件類型後,就可以直接定義文件類型的變量了。例如:
  var List1: PhoneList;
  有時侯,我們也可以使用file of基類型的方式直接定義文件類型變量。例如下面的定義與上面的形式有同樣的效果:
  var List1: file of PhoneEntry;
  如果我們在聲明文件類型時不指明其基類型。則這樣的文件我們稱之爲無類型文件,如:
  var DataFile: file;
  無類型文件主要用於直接訪問磁盤文件的多層I/O操作。6.3.4 指針類型指針類型對程序員來說可能是最複雜和最靈活的數據類型。當你在Delphi中創建一個數據結構時,首先要分配內存空間。分配的內存空間用於存儲數據結構中的數據。而指針就是指向分配空間的內存地址。使用指針,可以使程序不必每次需要時都去分配,只要申請一次即可,其它過程或函數使用同一塊內存空間時,只要使用該內存空間的地址。例如,假設你的一個鄰居問你怎樣去百貨店,你並不需要把整個百貨店搬到鄰居家裏,只需要告訴它去百貨店的路徑即可,這個路徑類似於一個指針。
1.指針類型的聲明
  聲明指針類型的語法規則見圖6.10。
  其中基類型可以是簡單類型,也可以是前面介紹的結構,或只是一個標識符。如果基類型是一個未定義的類型標識符的話,則該類型標識符必須在同一塊內聲明。
  下面是帶有指針類型聲明的例子:
type WordPtr =^Word;
RealPtr =^Real;
PersonType=Record LAstNAme:String;
FirstNAme:String; Age:Integer;
end;
PersonPointer = ^PersonType;
  上例中,聲明瞭三個指針類型,一個是WordPtr,指向^Word,一個是RealPtr,指向^Real,還有一個是PersonPointer,指向一個標識符,而該標識符標識一個記錄類型。
  聲明瞭指針類型之後,就可以聲明指針類型變量,
  例如:Var WP:WordPtr;
      RP:RealPtr;
      Person:PersonPointer;
2.指針的使用
  Delphi提供專門的過程和函數操作指針,這些過程和函數是:New過程,@操作符,PTR函數,GetMem過程。下面分別介紹。
(1)New過程
  New過程是 Pascal中的標準例程(在System單元聲明),用於在應用程序堆棧中爲動態變量申請一塊區域,並把該區域的地址賦予指針變量。New過程的語法爲:
  procedure New(var P: Pointer);
  其中P是一個指針變量。所分配區域的大小由指針變量P的基類型決定。如果在應用程序堆棧中沒有足夠的內存空間供分配,將觸發EOutOfMemory異常。
  新分配的內存空間由P指向,P^即爲類型的動態變量。應用程序不再需要該動態變量時,可以調用Dispose標準例程釋放爲該變量分配的內存空間。
 下面是使用New過程的舉例:
type PListEntry = ^TListEntry;
TListEntry = record
  Next: PListEntry;
  Text: string;
 Count: Integer;
end;
var List, P: PListEntry;
begin
...
New(P);
P^.Next := List;
P^.Text := 'Hello world';
P^.Count := 1;
List := P;
Dispose(P);
...
end;
  上例中,聲明瞭一個指針類型 PListEntry,指向標識符 TListEntry,而該標識符標識一個記錄類型 TlistEntry,然後定義了兩個指針變量List和P。程序首先用New過程在應用程序堆棧中爲動態變量申請一塊區域,並把該區域的地址賦予指針變量P。P^即爲記錄類型TListEntry的動態變量。不再需要該動態變量後時,調用Dispose釋放爲該變量分配的內存空間。
(2)@操作符
  @操作符是個一元操作符,用於獲得操作數的地址,其使用語法見圖6.11。
  從圖中可以知道,@後面的操作數可以是變量、過程、函數或類類型中的方法。
  程序示例如下:
procedure ChangeValue(X:Integer)
  Var IntPtr:^Integer;
begin
 IntPtr:=@X;
  Writeln(IntPtr^);
  IntPtr^:=20;
end;
  假設主程序如下:
begin
Param:=10;
ChangeValue(param);
Writeln(Param); {10}
end;
  上例中,ChangeVAlue過程首先聲明瞭一個指向整型數的指針Ptr,然後用@操作符取出X的地址賦予IntPtr指針,並顯示Ptr指針指向的數,最後改變這個數。
(3)PTR函數
  Ptr函數是 Pascal中的標準例程(在System單元聲明),用於把一個指定的地址轉換爲指針。Ptr函數的語法爲:
  function Ptr(Address: Integer): Pointer;
  其中Address是一個整數,用於表示一個32位地址,函數執行的結果是把32位地址轉化爲指針。
(4)GetMem過程
  GetMem過程也是Pascal中的標準例程(在System單元聲明),類似於New,用於在應用程序堆棧中爲動態變量申請一塊指定大小的區域,並把該區域的地址賦予指針變量。GetMem函數的語法爲:
  procedure GetMem(var P: Pointer; Size: Integer);
  其中P是一個指針變量,Size指定區域的字節數。
  所分配區域的大小由指針變量P的基類型決定。如果在應用程序堆棧中沒有足夠的內存空間供分配,將觸發EOutOfMemory異常。如果程序不再需要該動態變量時,可以調用FreeMem標準例程釋放爲該變量分配的內存空間。
 程序示例如下:
Var F: file;
Size: Integer;
Buffer: PChar;
begin
AssignFile(F, 'test.txt');
Reset(F, 1);
try
  Size := FileSize(F);
  GetMem(Buffer, Size);
  try
   BlockRead(F, Buffer^, Size);
   ProcessFile(Buffer, Size);
  finally
   FreeMem(Buffer);
  end;
finally
CloseFile(F);
end;
end;
  上例打開一個名字爲test.txt的文件,並把文件讀入動態分配的緩衝區,緩衝區大小爲文件的大小,然後對文件進行處理,最後釋放動態分配的緩衝區,並關閉文件。
  Pascal中有一個特殊的保留字nil,這是一個空指針常量,當指針的值爲nil時,表示指針當前沒有指向任何動態變量。值爲nil的指針變量不能訪問動態變量。
3.無類型指針
  無類型的指針是指指針變量在聲明時沒有指明基類型。無類型指針在聲明中只使用Pointer。例如:
  var pAnyPoint:Pointer;
  指針pAnyPoint可以指向任何變量類型。無類型的指針的作用是它可以指向任何類型,但是,不能用指針變量符後加^的形式來引用它的動態變量。
4.字符指針類型
  字符指針類型即PChar數據類型,是一個指向以NULL(不是零)字符結尾的字符(Char)串的指針。這種類型主要用於與外部函數如在Windows API中所用的函數兼容。與Pascal字符串不同,Windows和C字符串沒有一個長度字節。取而代之的是它們從0字節索引開始,以一個NULL(#0)結束。Pascal RTL字符函數根據長度決定存儲在字符串變量中的字符數目。C函數實際上一次搜索字符數組的一個字符,直到碰到NULL,表示字符串結尾。在Windows API中所用的許多函數以指向NULL結束字符串或用NULL結束填入緩衝區的字符。在Pascal中使用這些函數就需要PChar類型變量。內存將分配給變量並被所需函數使用。
  除了PChar外,Delphi還包含PAnsiChar和PWideChar數據類型。
  PAnsiChar數據類型是一個指向以NULL(不是零)字符結尾的AnsiChar字符串的指針,在Delphi中,PCHAR等同於PAnsiChar。
 ?PWideChar數據類型是一個指向以NULL(不是零)字符結尾的WideChar字符串的指針,用於UniCode字符集。實際上,PAnsiChar和PWideChar數據類型的定義爲:
type
  PAnsiChar = ^AnsiChar;
  PWideChar = ^WideChar;
  PChar = PAnsiChar;
  字符串類型與PCHAR類型賦值兼容,即一個字符串可以直接賦給一個PCHAR類型的變量,例如:
  var P: PChar;
   ...
  begin
  P := 'Hello world...';
  end;
  上面賦值語句首先申請一塊區域,該區域包含字符串 'Hello world...',並在最後加上NULL,然後P指向這塊內存區。上述例子等價於下列形式:
  const TempString: array[0..14] of Char = 'Hello world...'#0;
  var P: PChar;
  ...
 begin
  P := @TempString;
 end;
6.3.4 過程類型
  Object Pascal允許把過程和函數作爲一個整體賦給變量和作爲參數傳遞。實現這一功能的途徑是使用Object Pascal的過程類型。
 聲明一個過程類型的語法與聲明過程或函數的首部的語法相似,不同的是聲明一個過程類型時不需要過程或函數保留字後面的標識符。聲明過程類型時可以指定一種調用約定方式,缺省的調用方式是Register。下面是聲明過程類型的舉例:
type
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
  上例聲明的三個過程類型中,第一個是不帶任何參數的過程,第二個是帶一個參數S的過程,第三個是帶一個參數X的函數,函數返回值爲Double。
  過程類型根據其是否運用於對象分爲兩類:全局過程指針和方法指針。
  聲明過程類型時不帶of Object的是全局過程指針。全局過程指針指向的是全局的過程或函數。例如上面的過程類型Tprocedure,TstrProc,TMathFunc都是全局過程指針。
  聲明過程類型時帶有of Object的是方法指針。方法指針指向的是一個對象的過程或函數方法。例如下面的過程類型是方法指針。
type TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
  聲明過程類型變量的方法與聲明其它類型變量的方法相同,下面例子聲明兩個過程類型變量:
var Proc:TProcedure;
  StrProc:TStrProc;
  過程類型變量的值可以取下列四種之一:
 nil一個過程類型變量
 一個全局過程或函數標識符一個方法指示符下面舉例說明過程類型的用法。
type TMainForm = class(TForm)
  procedure ButtonClick(Sender: TObject);
  ...
  end;
var MainForm: TMainForm;
  MathFunc: TMathFunc;
  OnClick: TNotifyEvent;
function Tan(Angle: Double): Double;
  begin
   Result := Sin(Angle) / Cos(Angle);
  end;
  上例的TMainForm是一個類類型,TMathFunc是前面定義的全局過程指針,TnotifyEvent是前面定義的方法指針。其中MathFunc和OnClick是兩個過程類型變量。變量MathFunc和OnClick的賦值方式爲:
  MathFunc := Tan;OnClick := MainForm.ButtonClick;
  調用結果爲:
X := MathFunc(X);{等價於 X := Tan(X) }
OnClick(Self);{等價於 MainForm.ButtonClick(Self) }
  過程類型變量值等於NIL表示該過程類型變量沒有賦值,因此在過程語句或函數調用中使用值等於NIL的過程類型變量將發生錯誤。防止的辦法是使用Assigned()函數。例如:
  if Assigned(OnClick) then OnClick(Self);
  如果給定的過程類型變量已經賦值,Assigned函數返回TRUE,如果給定的過程類型變量值爲NIL,Assigned函數返回FALSE。在把一個過程或函數賦給一個過程類型變量時要注意賦值兼容,必須滿足下列條件:調用約定方式必須相同。?參數個數必須相同,相應的數據類型必須相同。?函數返回的值類型必須相同。
6.3.5 Variant數據類型
  Variant主要用於表達需要動態改變類型的數據。例如,當一個數據的實際類型在編譯時不知道或運行時需要改變類型時,就可以使用Variant類型。
  Variant類型變量可以包含integer, real, string, boolean, 日期和時間等類型值或以及 OLE自動化對象等,還可以表示長度和維數可變的數組。
  Variant變量在首次創建時,總是被初始化爲Unassigned。Unassigned是Variant變量的一個特殊值,表明Variant變量還未賦值,Variant變量的另一個特殊值是NULL,指示Variant變量未知或丟失數據。
6.4 數據類型的轉換
  Object Pascal是一種類型嚴謹的程序設計語言,不是所有類型的數據都可以互相賦值的。只有賦值兩邊的數據類型一致或兼容纔可以進行賦值操作。下面就有關數據類型兼容和強制數據類型轉換等概念進行介紹。
6.4.1 類型兼容
  所聞類型兼容,是指一種類型的數據可以與另一種類型的數據進行關係運算。類型兼容是賦值兼容的前提條件,也是Object Pascal數據運算的基本前提。
?Object Pascal規定,只有滿足下列條件纔是類型兼容:
?兩種類型都一致。
?兩種類型都是實型。
?兩種類型都是整型。
?一種類型是另一種類型的子界。
?兩種類型都是另一種宿主類型的子界。
?兩種類型都是另一種兼容基類型的集合類型。
?兩種類型都是緊湊字符串類型,並具有相同的元素個數。
?一種類型是字符串類型,另一種類型是字符串類型、緊湊字符串類型或字符類型。
?一種類型是Pointer類型,另一種類型是任意的指針類型。
?兩種類型都是類類型或,類引用類型,並且一種類型繼承了另一種類型。
?一種類型是PChar類型,另一種類型是形式爲array[0..X] of Char的字符數組。
?兩種類型都是基類型相同的指針類型(編譯開關$T設置爲{$T+})。
?兩種類型都是結果類型相同、參數個數相同、參數類型一致的過程類型。
?一種類型是Variant類型,另一種類型是整型、實型、字符串類型或布爾類型。
  當兩個類型要進行關係運算操作而又不滿足類型兼容時,將產生編譯錯誤。
6.4.2 賦值兼容
  類型兼容僅僅可以進行關係運算,只有賦值兼容的變量纔可以賦值或進行參數傳遞。
  類型T2的值與類型T1的值賦值兼容是指T1和T2允許賦值操作,即:
  T1:=T2;
  Object Pascal規定,類型T1的值與類型T2的值賦值兼容必須有滿足下列條件:
?T1和 T2類型相同,並且都不是文件類型或包含文件類型的自定義類型。
?T1是T2是兼容的有序類型,類型T2的值在類型類型T1的取值範圍內。
?T1和 T2都是實型, 類型T2的值在類型T1的取值範圍內。
?T1是實型,T2是整數型。
?T1和 T2都是字符串類型。
?T1是字符串類型,T2是字符類型。
?T1是字符串類型,T2是緊湊的字符串類型。
?T1是長字符串類型,T2是PChar類型。
?T1和T2是兼容的、緊湊的字符串類型。
?T1和T2是兼容的、集合類型。 類型T2的所有成員在類型T1的取值範圍內。
?類型T2在類型T1的取值範圍內。
?T1和T2是兼容的指針類型。
?T1是類類型,T2是T1的繼承類類型。
?T1是類引用類型,T2是T1的繼承類引用類型。
?T1是PChar類型,T2是字符串常量。
?T1是PChar類型,T2是形式爲array[0..X] of Char的字符數組。
?T1和T2是兼容的過程類型。
?T1是過程類型,T2是具有與T1嗤峁嘈拖嗤⒉問鍪嗤⒉問嘈鴕恢碌墓袒蠔?br> ?T1是Variant類型,T2是Integer,real,string或boolean類型。
?T1是Integer,real,string或boolean類型,T2是Variant類型。當兩個類型要進行賦值操作而又不滿足賦值兼容時,將產生編譯錯誤。
6.4.3 變量強制類型轉換
  變量強制類型轉換就是強制將一種類型變量轉換爲另一種類型的變量。程序員自己確定強制類型轉換的合法性。
  圖6.13是變量強制類型轉換的語法規則。
  當變量強制類型轉換應用於一個變量時,該變量就被視爲由類型標識符說明的類型。變量的大小必須與類型標識符說明的類型的大小相同。變量之前可以放置一個或多個類型允許的限定符。
  Word類型的變量W轉換爲TByteRec, TWordRec(L)將一個LongInt類型的變量L轉換爲TWordRec類型,而PByte(L)則將LongInt類型變量L轉換爲指針類型Pbyte。
6.4.4 數值強制類型轉換
  數值強制類型轉換就是強制將數值(或表達式)從一種類型轉換爲另一種類型。 
  其中表達式類型必須是有序類型或指針類型。 在轉換中,如果結果類型的大小不同於表達式類型的大小,則有可能造成數據的截止或擴展。下面舉例說明數值強制類型轉換的用法。
Integer('A')//把字符A轉換爲一個整數。
Char(48)//把數字48轉換爲一個字符。
Boolean(0)//把數字0轉換爲一個布爾值。
Longint(@Buffer)//把指針轉換爲一長整數。
Int64(I)//把一個整數轉換爲64位整數
6.5 數據類型運算符
操作符 操作  操作數據類型 結果數據類型
DIV  整數除  integer   integer
mod  餘數除  integer   integer
mod運算符的結果是兩個操作數相除後的餘數的整數部分。
shl  按位左移 integer   Boolean
shr  按位右移
in  屬於
6.5.4 運算符的優先級
運算符              優先級  分類
@, not              1 (最高) 一元運算符
*, /, div, mod, and, shl, shr, as 2     乘法運算符
+,-, or, xor           3     加法運算符
=, <>, <, >, <=, >=, in, is    4 (最低) 關係運算符
6.6 語 句
  這些例子都是DOS窗口方式的,而不是通常的Windows應用程序。如果讀者要調試這些程序,需要修改Delphi的一些缺省設置。其步驟是:
(1)開始Delphi。
(2)如果當前不是自動打開一個新項目 ,選擇File|New命令開始一個新項目 。
(3)選擇Project|Options|Linker命令,使能Generate Console Application覈對框,從而是Delphi創建的程序是DOS窗口方式的,而不是通常的Windows應用程序。
(4)選擇View|Project Source命令,進入代碼編輯器編輯項目 文件代碼,鍵入本書提供的例子。
(5)運行程序,程序將在它自己的DOS窗口運行。要關閉DOS窗口,選擇Alt+F4或單擊窗口的右上角單擊X。
6.6.1 賦值語句
6.6.2 塊語句
1.ASM/END塊語句
  ASM塊語句在Pascal中嵌入彙編語言代碼。由於Delphi Pascal對計算機資源提供了很好的支持,因此,除非特別需要,一般不需要使用匯編語句。
2.BEGIN/END塊語句
6.6.3 Delphi控制語句
 Object Pascal使用控制語句來控制程序的執行順序。7個是分支語句,3個是循環語句:
.分支語句
. if 語句
. case語句
 CASE Choice of
  '1': EvaluateChoice;
  '2': Initialize
  ELSE Writeln('Bad Choice,Try Again.');
 END;
  請注意,CASE語句的常量範圍不能重疊。Else要放在所有判斷語句之後.
. GOTO語句
  GOTO語句強行將程序轉向一個指定的點執行。該指定點用一個標號標識。
. Break語句
. Continue語句
. Exit語句
  EXIT語句的功能是退出當前的代碼塊。如果代碼塊是主程序,EXIT語句導致程序的終止;如果當前塊是嵌套的,EXIT語句跳到外一層嵌套繼續執行。如果當前塊是過程或函數,EXIT語句導致過程或函數執行終止,跳到調用過程或函數的語句的下一條語句執行。
. Halt語句
  HALT語句導致程序的非正常結束,並返回到操作系統。通常是在程序遇到致命錯誤時才使用HALT語句。HALT語句後可跟一個整數代碼HALT(1),以指定錯誤的原因。
. 循環語句
. Repeat/Until語句
  REPEAT
   Key:=GetChar;
   Writeln('Key IS',key);
   UNTIL Key=$D;
. While語句
  WHILE key<>$D DO key:=GetChar;
. for語句
  for V := Expr1 to Expr2 do Body; 可使用DOWNTO;在循環體中,如果不想執行循環下面的語句,而直接進入下一次循環,可以使用Continue語句.
  要退出循環,跳到FOR/DO語句下面的語句執行,可以使用break語句;如果不想執行循環下面的語句,而要求直接進入下一個循環,可以使Continue語句。
6.7 過程與函數
6.7.1 過程的定義和調用
  要定義和調用一個過程,首先要在程序的TYPE區聲明一個過程.
 下面是一個過程聲明的例子:
procedure NumString(N: Integer; var S: string);
  過程聲明之後,就應當在Implementation區定義這個過程,定義的規則如下。過程:
Procedure <name>(<Parameters>)
<declarations>
BEGIN
<statements>
END;
6.7.2 函數的定義和調用
  函數的定義和調用與過程的定義和調用類似,不同的是函數的首部,函數的首部多了一個返回結果類型。
 function Max(A: Vector; N: Integer): Extended;
  Max函數返回類型爲Extended。函數聲明之後,就應當在Implementation區定義這個函數。
6.7.3 返回值
(1)返回值直接送給函數名。
(2)返回值送給Delphi的一個內置變量Result。
 如果你寫的函數有可能移植到其它Pascal編譯器中使用,最好使用第一種方式。
6.7.4 調用約定
  從前面說明的過程和函數的語法規則我們知道,在聲明過程或函數時,可以在附屬塊指定過程或函數的參數的傳遞方式。Pascal共提供了五種傳遞方式,分別爲Register,Pascal,Cdecl,Stdcall,SafeCall。缺省的調用方式是Register方式。如果一個過程或函數沒有指定過程或函數的調用方式,就採用Register調用方式。
  調用方式的語法示例如下:
  function Max(A: Vector; N: Integer): Extended;Stdcall;
  Object Pascal調用方式的區別於以下幾點:
(1)傳遞參數的順序
  Register和 Pascal調用方式傳遞參數是從左到右,即最左邊的參數先產生並首先傳遞,最右邊的參數最後產生並最後傳遞。而Cdecl, Stdcall和 Safecall 調用方式傳遞參數則是從右到左。
(2)堆棧中刪除參數
  使用Pascal、Stdcall和Safecall調用方式的過程或函數在返回時程序自動刪除堆棧中的參數,而Cdecl調用方式必須在程序返回時調用者自己刪除堆棧中的參數。
(3)使用寄存器傳遞參數
  Register調用方式使用三個CPU寄存器來傳遞參數,而其它調用方式使用堆棧來傳遞參數。
  Register調用方式通常是最快的參數傳遞方式,因爲它不需要創建棧幀。Pascal和 Cdecl調用方式通常用於調用用C,C++或其它語言書寫的動態鏈接庫程序。Stdcall 調用方式通常用於Windows API程序。而Safecall調用方式通常用於實現OLE自動化編程的雙接口(Dual interfaces)。
6.7.5 指示字
  在聲明過程或函數時,可以在附屬塊使用指示字以進一步指定過程或函數的產生方式。Delphi過程或函數分別提供了Block,External,Asm,Forward。指定調用方式的語法示例如下:
  procedure MoveWord(var Source, Dest; Count: Integer); external;
  其中Block是缺省方式,表示過程或函數的語句部分是 Pascal程序快,下面對External,Assembler,Forward進行介紹。
1.External
  該指示字表示過程或函數是外部的,通常用於從動態鏈接庫中引入過程或函數。External後可以動態鏈接庫名或表示動態鏈接庫的有序數,也可以指定引入的過程或函數名。例如:
  function MessageBox(HWnd: Integer; Text, Caption: PChar; Flags: Integer): Integer; stdcall; external 'user32.dll' name 'MessageBoxA';
  上例中,user32.dll指定用於引入過程或函數的動態鏈接庫名(也可以是一個有序數),MessageBox指定從動態鏈接庫中引入過程或函數名。
(2)Assembler
  該指示字表示過程或函數是使用嵌入式彙編語言編寫的。例如函數聲明:
 function LongMul(X, Y: Integer): Longint;Assembler
  其定義爲:
  function LongMul(X, Y: Integer): Longint;
(3)Forward
  該指示字表示一個過程或函數是向前查找的。在聲明瞭一個過程或函數是向前查找的之後,該過程或函數的定義必須在後面的某個地方定義。
procedure Walter(M, N: Integer); forward;
procedure Clara(X, Y: Real);
begin
...
Walter(4, 5);
end;
procedure Walter;
begin
...
MessageBeep(0);
end;
 注意:不能在單元的interface部分聲明向前查找過程。在使用向前查找過程時,要注意相互遞歸。
6.7.6 參數
  當調用過程或函數時,常常需要使用參數傳遞數據給被調用的過程或函數。在某種程度上,使過程、函數更有用更靈活的方法就是使用參數。
  在Pascal中,調用過程或函數使用的參數稱爲實參,被調用過程或函數使用的參數稱爲形參,例如,下面語句中,Edit1是實參:
  ColorIt(Edit1);
  下面的AnEditBox是形參:
  Procedure ColorIt(AnEditBox:Tedit);
  Delphi傳遞參數的方式有四種:
(1)傳值(Passing By Value)。
  變量和結構被完整地拷貝到堆棧中,而不是通過機器的寄存器。通過值傳遞參數可以防止調用的函數修改原來的參數,因爲調用的函數接收到的只不過是參數的一個副本。例如:
procedure Tform1.Button1Click(Sender:Tobject);
var Number:Integer;
begin
  Number:=StrToInt(Edit1.text);
  Calculate(Number);
  Edit2.Text:=IntToStr(Number);
end;
Procedure Calculate(CalcNo:Integer);
begin
 CalcNo:=CalcNo*10;
end;
  在Calculate過程中,CalcNo參數按值傳遞,執行該過程後,CalcNo的值擴大了十倍。但是,調用過程Tform1.Button1Click中Number並沒有改變,因此Edit1編輯框與Edit2編輯框的值一樣。
(2)傳引用(Passing By Reference)。
  傳遞一個指向參數的引用(指針),按規則引用可用作指針和值。改變引用傳遞的參數要影響調用源參數的拷貝。
  使用傳引用必須在參數前加上Var保留字。例如,把Calculate改寫如下:
  procedure Calculate(Var CalcNo:Integer);
  begin
   CalcNo:=CalcNo*10;
  end;
  修改後,Calculate過程的CalcNo參數爲按引用傳遞,執行該過程後,CalcNo的值擴大了十倍,同時,調用過程Tform1.Button1Click中Number也作了改變,因此Edit2編輯框的值是Edit1編輯框值的10倍。
(3)常量傳遞(Constant Parameters)。
  如果過程或函數運行時,形參的值永遠都不會改變,就可以考慮使用常數參數。要使一個參數爲常數參數,只要在參數前加上Const保留字。例如:
function TDirectoryOutline.ForceCase(const AString: string): string;
begin
  if Assigned(FCaseFunction) then
   Result := FCaseFunction(AString)
  else
   Result := AString;
end;
  當你不需要參數改變時,可以使用常數參數防止偶然對該參數的修改。如果程序某個地方對常數參數進行了修改,你將會得到一個非法變量引用錯誤信息。
(4)默認參數
  在Delphi中,可以爲過程和函數定義默認參數。默認參數僅僅顯示在參數列表的尾部,其形式是:
  參數名: 類型 = 值
  當調用包括默認參數的過程或函數時,默認參數的值可以省去。例如下面是一個函數的定義:
procedure FillArray(A: array of Integer; Value: Integer = 0);
  下面是兩個合法的調用語句:
FillArray(MyArray, 1);//直接傳遞值
FillArray(MyArray);//使用默認參數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章