Delphi中的各種字符串、String、PChar、Char數組


參考博客:http://www.cnblogs.com/pchmonster/archive/2011/12/14/2287686.html

 

其中的所有代碼均在Delphi7下測試通過。

Delphi 4,5,6,7中有字符串類型包括了:

  • 短字符串(Short String)
  • 長字符串(Long String)
  • 寬字符串(Wide String)
  • 零結尾字符串(Null-Terminated String)、PChar和字符數組

1、短字符串(Short String)

固定長度,最大字符數個數為255,短字符串也稱為長度字節(Length-byte)字符串,這是因為短字符串的第0個元素包含了這個字符串的長度(字符串中字符的個數)。因此ShortString的缺省最大長度為256個字節(255個字符+1個長度字節=256),聲明一個短字符串有兩種方式,如下:

var
  S: ShortString;   { 255個字符長度,256個字節}
  S1: String[255];  { S1和S的字符類型一樣,通過使用String聲明字符串並且在String后面用中括號規定字符個數的形式定義字符串}
  Len: Integer;
begin
  S := 'Hello';
  Len := Ord(S[0]); { Len現在包含S的長度為5,Ord函數可以把一個字符類型轉換為整數類型}
  Len := SizeOf(S); { Len現在包含的是ShortString類型的大小,為256字節,並不是字符串的長度} 
end;

  

以上例子通過S[0]可以獲得S的字符串長度,當然也可以用Length函數來確定一個短字符串的長度。

可以通過數組的下標來訪問ShortString中的一個特定位置的字符,具體使用參看下面例子和注釋說明:

var
  S: string[8];{這種定義方式,是定義S是一個字符串,且S是最多含有8個字符的字符串}
  i: Integer;
begin
  S := 'a_pretty_darn_long_string';
  { 因為S只有8個字符大小,
  因此s的實際存儲的內容為“a_pretty”}
  i := 10;
  S[i] := 's';
  { 因為S只有8個字符大小,
  試圖改寫第10個元素,將會使內存混亂}
end;

  

2、長字符串(Long String)

長字符串 (AnsiString)是一種動態分配的字符串,其大小只受可用內存的限制。聲明一個長字符串,只需要用關鍵字String不加大小參數即可

在Delphi 7中AnsiString包含的字符是用單字節存儲的。

var
  S: string;

  

由於是動態分配的,一次可以隨意修改字符串,而不用擔心對其他的影響,也不用擔心越界的問題。String類型沒有0元素,試圖存取String類型的0元素會產生一個編譯錯誤。

通過Length函數也可以獲得長字符串的長度,也可以通過SetLength過程為長字符串設置長度。其在內存中分配情況如下:

0013

 

  注意當給一個String類型賦值時候,賦的字符串太長,可能會報錯:“String  literals may have at most 255 elements”。這時候你就納悶了:不是說String的字符個數沒有限制的嗎?

  對於這個問題,我們給個代碼示例(程序1

var
    s: string;
begin
    s:= '<?xml version="1.0" encoding="UTF-8"?><Msg><AppHdr><CharSet>UTF-8</CharSet><Fr>000100</Fr><To>SDC</To><BizMsgIdr>0000000002</BizMsgIdr><MsgDefIdr>V1.0</MsgDefIdr><BizSvc>067</BizSvc><CreDt>20130227100434</CreDt><Sgntr>fb3LY5VmhonZwhP+ntxI9A==</Sgntr></AppHdr><Document><Data><FndNm>name</FndNm><TtlFndVol>12681656.00</TtlFndVol><FndCd>159999</FndCd><FndSts>0</FndSts><NAV>1.0251</NAV><NtValDt>20130301</NtValDt><NtValTp>0</NtValTp></Data></Document></Msg>';
    
end.

  這個時候,將一個長度大於255的字符串直接賦值給string類型的變量就會報上面所說的錯誤。可以替代的辦法是將一個較長的字符串分成多份,在賦值時候使用+ 再賦值,見例子(程序2

var
    s: string;
begin
    s:= '<?xml version="1.0" encoding="UTF-8"?><Msg><AppHdr><CharSet>UTF-8</CharSet><Fr>000100</Fr><To>SDC</To>'
    + '<BizMsgIdr>0000000002</BizMsgIdr><MsgDefIdr>V1.0</MsgDefIdr><BizSvc>067</BizSvc><CreDt>20130227100434</CreDt>'
    + '<Sgntr>fb3LY5VmhonZwhP+ntxI9A==</Sgntr></AppHdr><Document><Data><FndNm>FundName</FndNm><TtlFndVol>12681656.00</TtlFndVol>'
    + '<FndCd>159999</FndCd><FndSts>0</FndSts><NAV>1.0251</NAV><NtValDt>20130301</NtValDt><NtValTp>0</NtValTp></Data>'
    + '</Document></Msg>';

end.

  這個時候就可以編譯成功了

3、寬字符串(Wide String)

寬字符串和長字符串一樣,大小只受有效內存的限制,並實行動態分配。

在Delphi 7 中WideString被實現為2個字節存儲一個字符,用WideString來處理多字節字符(比如漢字)是十分方便的。如:

var
  S: string;
  { 在Delphi 7中默認string等同於AnsiString}
  WS: WideString;
begin
  S := '世界你好';
  WS := S;
  ShowMessage(S[1]);  { 此時無任何顯示,因為S[1]取出的是‘世’的一半}
  ShowMessage(WS[1]); { 顯示‘世’}
end;

  要理解寬字符串就必須理解字符編碼的規則,比如ASCII、UTF-8……

 

4、零結尾字符串(Null-Terminated String)、PChar和字符數組

在C和C++中沒有真正的字符串數據類型,都是通過以Null結尾(0)的字符數組來實現的,字符數組沒有長度字節,因此只能通過結尾的Null標志來作為字符串的字符結束標志。又因為Windows是用C編寫的,很多Windows函數要用到以字符數組作為參數,但Pascal字符串類型不是字符數組,因為為了讓Pascal字符串也能與Windows兼容,就需要一個字符串數組,PChar類型正是符合這種需求,在任何需要字符數組的地方都可用PChar。

雖然AnsiString和WideString都已經實現了NULL

相應的也有PAnsiChar和PWideChar,分別對應於AnsiChar字符和WideChar字符。

例如:Windows MessageBox函數,此函數聲明如下:

function MessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall;

  

第二個和第三個參數需要一個指向字符數組的指針,為了可以調用此函數,有以下三種方法來實現

1、PChar()類型轉換

var
  Text: string;
  Caption: string;
begin
  Text := 'This is a test.';
  Caption := 'Test Message';
  MessageBox(0, PChar(Text), PChar(Caption), 0);
  { 這里PChar用來把string類型轉換為Null結尾的字符串}
end;

 其中

2、PChar變量

我們先做一個實現,看看PChar類型到底是啥呢?

運行下面程序:

var
  Text: PChar;    { 聲明為PChar類型}
  Str: string;    { 聲明為String類型}
begin
  Text := 'This is a test.';             { 都被賦予了相同的字符串}
  Str := 'This is a test.';
  ShowMessage(IntToStr(SizeOf(Text)));   { 4字節,實質是指針}
  ShowMessage(IntToStr(SizeOf(Str)));    { 也是4字節,也是指針}
end;

  

通過上面的程序,我們知道Text(PChar類型)只不過是一個指針而已。

var
  Text: PChar;
begin
  Text := 'This is a test.';
  MessageBox(0, Text, 'Test Message', 0);
  { 這里Text直接聲明為了PChar類型,字符串常量可以直接用}
end;

  

指針Text指向了這樣一個內存區域,一個包含Null的結尾的 'This is a test.' 字符串的區域。其等同於下面的代碼:

const
  TempString: array[0..15] of Char = 'This is a test.'#0;
var
  Text: PChar;
begin
  Text := @TempString[0];
  {Text指向Null結尾的TempString字符數組的第0個元素的地址,
  也就是整個字符數組的首地址}
  MessageBox(0, Text, 'Test Message', 0);
end;

  

3、Char類型字符數組

最后還可以用Char數組來代替PChar,代碼如下:

小心內存訪問越界的情況的出現

var
  Text1: array[0..14] of Char;  { 大小為15個字符}
  Text2: array[0..20] of Char;  { 大小為21個字符}
begin
  Text1 := 'This is a test.';   {Text1和Text2的字符長度都為15個字符}
  Text2 := 'This is a test.';
  MessageBox(0, Text1, 'Test Message 1', 0);
  {因為Text1的字符長度超過了其聲明的大小,因為會內存訪問混亂,顯示換亂}
 
  MessageBox(0, Text2, 'Test Message 2', 0);
  {Text2的字符長度比起聲明的大小要小,因為正常訪問,顯示正確}
end;

  

顯示結果如下:

0014   0015

關於字符串就先淺淺的談到這個,以后再深入了解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM