它是壹個字符串列表類型,由PASCAL系統管理,並作為數組使用,但其大小是動態的,即它本質上是由壹個鏈表實現的,基於鏈表數據結構。這個東西是壹個常見的東西,經常用來組織壹串字符串,也就是String類型的數據。網上有很多關於TStrigList用法的討論,可以從百度下載。
String是壹種存儲字符串的數據類型。
Delphi中字符串類型原理介紹
Delphi中字符串的操作很簡單,但幕後的情況相當復雜。Pascal的傳統字符串操作方法與Windows不同,它吸收了C語言的字符串操作方法。32位Delphi中添加了長字符串類型,該類型功能強大,是Delphi的默認字符串類型。
字符串類型在Borland公司的TurboPascal和16位Delphi中,傳統的字符串類型是壹個字符序列,序列的頭是壹個長度字節,表示當前字符串的長度。因為只有壹個字節用於表示字符串的長度,所以字符串不能超過255個字符。這種長度限制對於字符串操作來說很不方便,因為每個字符串的長度必須是固定的(最大值為255),當然您也可以聲明較短的字符串以節省存儲空間。
字符串類型類似於數組類型。事實上,字符串幾乎是字符類型的數組,因此您可以使用【】符號訪問字符串中的字符這壹事實充分說明了上述觀點。
為了克服傳統Pascal字符串的局限性,32位Delphi增加了對長字符串的支持。因此* * *有三種類型的字符串:
短弦
短弦類型也是上面提到的傳統帕斯卡弦類型。這種字符串最多只能有255個字符,與16位Delphi中的字符串相同。短字符串中的每個字符都屬於
ANSIChar類型(標準字符類型)。
分配
長字符串類型是新添加的可變長度字符串類型。這種字符串由內存動態分配,並使用引用計數,並使用寫入時復制技術。這種字符串的長度沒有限制(它可以
存儲多達20億個字符!),其字符類型也是ANSIChar類型。
寬弦
長字符串類型和分配
除了它基於WideChar字符類型(雙字節Unicode字符)之外,類型是相似的。
使用長字符串
如果字符串被簡單地定義為字符串,它可能是短字符串或ANSI長字符串,具體取決於$H編譯指令的值,$ H+(exact province)代表長字符串(ANSIString類型)。長字符串是Delphi庫中控件使用的字符串。
Delphi長字符串基於引用計數機制,通過引用計數來跟蹤內存中引用同壹字符串的字符串變量,並在字符串不再使用時即引用計數為零時釋放內存。
如果要增加壹個字符串的長度,而該字符串附近沒有空閑內存,也就是說,在同壹存儲單元中沒有擴展該字符串的空間,則必須將該字符串完全復制到另壹個存儲單元中。當這種情況發生時,Delphi運行時支持程序將以完全透明的方式為字符串重新分配內存。為了有效地分配所需的存儲空間,您可以使用SetLength過程來設置字符串的最大長度,例如:
集合長度
(String1,
200);
SetLength進程只完成壹個內存請求,並不實際分配內存。它只是保留了將來需要的內存,但實際上並沒有使用這些內存。這項技術起源於Windows操作系統,現在正被
Delphi用於動態分配內存。例如,當您請求大型陣列時,系統將保留陣列內存,但內存不會分配給陣列。
通常情況下,您不需要設置字符串的長度,但是當您需要將壹個長字符串作為參數傳遞給API函數(在類型轉換之後)時,您必須使用SetLength為該字符串保留內存空間,我將在後面解釋這壹點。
看壹下內存中的字符串
為了幫助您更好地理解字符串的內存管理細節,我編寫了壹個簡單的示例StrRef。在程序中,我聲明了兩個完整的字符串:Str1和Str2。按下第壹個按鈕時,程序會將壹個字符串常量賦給第壹個變量,然後將第壹個變量賦給第二個變量:
Str1
:=
‘妳好’;
Str2
:=
str 1;
除了字符串操作之外,該程序還使用以下StringStatus函數在列表框中顯示字符串的內部狀態:
功能
字符串狀態
(常量
Str:
字符串):
字符串;
開始
結果
:=
地址:
'
+
IntToStr
(整數
(Str))
+
,
長度:
'
+
IntToStr
(長度
(Str))
+
,
參考資料:
'
+
IntToStr
(品特格
(整數
(Str)
-
8)^)
+
,
價值:
'
+
Str
結束;
在StringStatus函數中,傳遞帶有常量參數的字符串非常重要。通過復制(value參數)傳遞會產生副作用,因為在函數執行過程中會產生對字符串的額外引用;相反,通過引用(var)或常量(const)參數傳遞不會產生這種情況。因為此示例不希望修改字符串,所以選擇了常量參數。
為了獲得字符串的內存地址(這有助於識別字符串的實際內容並觀察兩個不同的字符串變量是否引用同壹個內存區域),我通過類型映射將字符串類型強制轉換為整數。字符串實際上是壹個引用,即指針:字符串變量保存字符串的實際內存地址。
為了提取引用計數信息,我利用了壹個鮮為人知的事實:字符串長度和引用計數信息實際存儲在字符串中,它位於實際內容和字符串變量所指向的內存位置的前面,字符串長度的負偏移量為-4(使用Length函數很容易獲得該值),引用計數的負偏移量為-8。
但是,必須記住,上述關於偏移量的內部信息在未來的Delphi版本中可能會發生變化,並且很難保證沒有寫入官方Delphi文檔的功能在未來保持不變。
通過運行此示例,您將看到兩個字符串具有相同的內容、相同的內存位置和引用計數2,如圖7.1中列表框頂部所示。現在,如果您更改其中壹個字符串的值,更新後的字符串的內存地址也將更改。這是寫入時拷貝技術的結果。
第二個按鈕(Change)的OnClick事件代碼如下,結果顯示在列表框7.1的第二部分:
程序
TFormStrRef。BtnChangeClick(發件人:
to subject);
開始
Str1
[2]
:=
‘a‘;
列表框1。項目。添加
(‘str 1
[2]
:=
‘‘a‘‘);
列表框1。項目。添加
(‘str 1
-
'
+
字符串狀態
(str 1));
列表框1。項目。添加
(Str2
-
'
+
字符串狀態
(str 2);
結束;
請註意,BtnChangeClick只能在BtnAssignClick執行後執行。因此,程序啟動後無法使用第二個按鈕(按鈕的Enabled屬性設置為False);在第壹個方法結束後激活第二個按鈕。您可以自由擴展此示例,並在其他情況下使用StringStatus函數來探索長字符串的特征。
動態分配可以使用任何內存分配函數,
事實上,系統最終調用GetMem。
其他New、AllocMem、SetLength等。除了調用GetMem之外,只需進行壹些初始化即可,例如清除內存。釋放可以用Dispose或FreeMem來完成,
系統最終調用FreeMem,
Dispose相當於Finalize(p);
FreeMem(p);
Finalize的功能只是自動釋放結構或數組中的字符串和動態數組。
FreeMem直接釋放指針指向的內存,例如:
類型
TMyRec
=
記錄
名稱:
字符串;
x,
y:
整數;
結束;
PMyRec
=
^tmyrec;
定義變量
MyRec
:
PMyRec
開始
新的(MyRec);
//
編譯器會根據MyRec的大小自動計算要分配的內存量,然後生成代碼調用GetMem並清除其中的Name字段。
邁雷克。名字
:=
str1
+
str2
處置(MyRec);
//
除了調用FreeMem釋放MyRec結構的內存外,還會自動清除Name使用的內存(如果Name指向的字符串引用計數= 1);
//
FreeMem(MyRec);
& lt-
如果直接調用FreeMem來釋放MyRec,
這將導致內存泄漏,
因為邁雷克指向的弦。名稱未發布(引用計數-1)。
結束;
由於delphi對字符串的內存管理的特殊性,
有許多技術可以充分利用其優勢來生成非常高效的代碼。
例如,要使用TList保存字符串(而不是TStringList),
通常的做法是在TList中保存壹個PString指針。項目【I】。
所以妳需要重新分配壹塊內存並復制原來的字符串。
在大量數據的情況下效率非常低,
但是如果充分利用string的引用計數和強制類型轉換技巧,
您可以直接將字符串保存為TList中的指針。項目【I】:
例如:
定義變量
列表:
TList
GlobalString1
全球字符串2:
字符串;
...
程序
測試;
定義變量
tmp:
字符串;
開始
終端監督程式(Terminal Monitor Program的縮寫)
:=
global string 6 5438+0+global string 2;
列表。Add(指針(tmp));
//
將tmp作為指針保存到列表中。
{
由於tmp在測試過程結束時自動釋放,
如果直接退出,無效指針將保存在列表中。
所以我們要欺騙編譯器,
讓它認為tmp已經被釋放,
它相當於在不更改tmp引用計數(當前為1)的情況下執行tmp。
:=
‘‘的聲明,
由於直接tmp
:=
將修改引用計數並可能釋放內存。
所以使用強制類型轉換將tmp轉換為整數,並將該整數設置為0(即nil)。
該語句完全等同於指針(tmp)
:=
零;
這只是個人喜好。我喜歡使用整數
:=
只有0。
}
整數(tmp)
:=
0;
結束;
1.
Delphi編譯器在內部支持字符串(預定義
或者
內置)是Delphi的壹種基本數據類型,PChar只是壹個指向以零結尾的字符串的指針;
2.
線
存儲的字符串在堆中分配內存,字符串變量實際上是指向以零結尾的字符串的指針,同時,它還有壹個引用計數(reference
Count)函數,並保存字符串長度,當引用計數為零時,自動釋放占用的空間。
3.將壹個字符串賦給另壹個字符串只是壹個簡單的指針賦值,不會產生復制動作,只會增加該字符串的引用計數;
4.將PChar變量類型分配給字符串。
變量類型將產生壹個真正的復制動作,即PChar指向的整個字符串將被復制到為string分配的內存中;
5.將string賦給PCCAR變量類型只是將string的指針值賦給PCCAR變量類型,string的引用計數不會因為該操作而改變,因為在這種情況下PCCAR將依賴於string。當string的引用計數為零時,PCCAR可能會指向無效的內存地址,因此您必須小心處理程序中的這種情況。
6.PCCar的運行速度比string快得多,但PCCar是壹種落後的管理字符串的方式,而string則以高效的管理取勝。PCCar的存在只是為了兼容早期的類型和操作系統(調用Windows)。
API中經常使用),建議正常使用string。