Delphi 字串類型與字元陣列/指標的內存關係與轉換規則
Delphi 的 string (AnsiString/UnicodeString) 內部包含動態字元陣列,但與靜態陣列 array[0..N] of Char、字元指標 PChar 有著微妙的相容與差異。理解它們的內存佈局、索引起始、#0 結尾約定,是避免存取違規 (AV) 的關鍵。
字串與字元陣列互轉
var
arr: array[0..5] of Char; // 靜態陣列,索引 0 起
str: string; // 動態字串,索引 1 起
begin
// 字串常量 → 靜態陣列 (自動截斷/補 #0)
arr := 'Delphi'; // arr[0]='D'..arr[5]='i',超出長度會截斷
ShowMessage(arr); // 'Delphi' (PChar 視角讀到 #0 結尾)
// 靜態陣列 → 字串變數 (自動尋找 #0 或用長度)
str := arr; // 'Delphi'
// 字串變數 → 靜態陣列 (編譯錯誤!類型不兼容)
// arr := str; // Error: Incompatible types
// 索引差異:字串從 1 起,陣列從 0 起
ShowMessage(str[1]); // 'D'
ShowMessage(arr[0]); // 'D'
end;
字元指標 (PChar) 與字元陣列的 #0 陷阱
var
arr: array[0..6] of Char; // 7 字元空間
p: PChar;
begin
arr := 'Delphi'; // arr[6] 未初始化,可能非 #0
// 直接賦值給 PChar 危險:PChar 尋找 #0 結尾,可能讀越界
// p := arr; // 風險!
// 正確:手動在最後放 #0
arr[Length(arr)-1] := #0; // arr[6] := #0
p := arr; // 安全
ShowMessage(p); // 'Delphi'
// #0 在中間會截斷顯示
arr[3] := #0; // 'Del' + #0 + 'phi'
p := arr;
ShowMessage(p); // 'Del' (截斷)
end;
編譯期字元陣列常量
const
arr1: array[0..5] of Char = 'Delphi'; // AnsiChar 版本
arr2: array[0..5] of AnsiChar = AnsiString('Delphi'); // 顯式 AnsiChar
begin
ShowMessage(arr1[0]); // 'D'
ShowMessage(arr2[0]); // 'D'
end;
內存佈局對照表
| 類型 | 索引起始 | #0 結尾 | 長度存儲 | 記憶體管理 |
| string (AnsiString/UnicodeString) | 1 | 有 (隱式) | 前置 4/8 位元組 | 引用計數、自動管理 |
| array[0..N] of Char | 0 | 無 (需手動) | 無 (編譯期常量除外) | 棧/靜態、固定大小 |
| ShortString / String[N] | 1 (元素) / 0 (長度位元組) | 無 | 第 0 位元組存長度 | 棧/靜態、固定大小 |
| PChar / PWideChar | 0 | 約定有 | 無 | 指標、無所有權 |
關鍵轉換規則速查
| 來源 → 目標 | 可行性 | 方法/注意 |
| 字串常量 → 靜態陣列 | ✅ | 直接賦值,超長截斷 |
| 靜態陣列 → 字串變數 | ✅ | 直接賦值,遇 #0 結束 |
| 字串變數 → 靜態陣列 | ❌ | 類型不兼容,需逐字元 Copy |
| 靜態陣列 → PChar | ⚠️ | 必須確保最後一元素為 #0 |
| string → PChar | ✅ | PChar(str) 取內部緩衝區指標 |
| PChar → string | ✅ | str := PCharPtr 自動複製至 #0 |
實戰避坑清單
- 永遠不要將 string 變數直接賦給靜態陣列 — 編譯不通過
- 陣列轉 PChar 前必須手動補 #0 — 否則讀越界導致 AV
- ShortString/String[N] 第 0 位元組是長度 —
Ord(str[0]) 可取長度,甚至可寫入修改長度
- API 需要緩衝區時 — 優先用
array[0..N] of Char 或 string + SetLength
- Delphi 2009+ 統一 Unicode —
Char=WideChar,PChar=PWideChar,ANSI 需顯式 AnsiChar/AnsiString
徹底搞清這些類型的邊界與轉換規則,能消除 90% 以上的字串相關存取違規與亂碼問題。
- 上一篇文章: Delphi 字串與 Windows API 互操作:PChar、緩衝區、記憶體管理完整指南
- 下一篇文章: Delphi String 內存結構揭秘:引用計數、長度前綴、#0 終結符與 Copy-on-Write 機制
Copyright ©
程式碼之家 All Rights Reserved