首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 內存操作函數詳解(一):字符指針內存分配與 StrAlloc 專項

     編輯:Delphi

字符指針 (PChar/PWideChar) 內存分配:StrAlloc 為何是最佳選擇

Delphi 提供十幾個內存分配函數,但針對字符指針 (PChar、PWideChar、PAnsiChar),StrAlloc 是專門設計、最安全、最高效的選擇。本文深度解析其原理與相關函數族。

函數族全景

GetMem      AllocMem      ReallocMem      FreeMem
GetMemory   ReallocMemory FreeMemory
New         Dispose
NewStr      DisposeStr
StrNew      StrAlloc      StrDispose      StrBufSize
GlobalAllocPtr GlobalFreePtr
WideStrAlloc AnsiStrAlloc
Move        MoveMemory    CopyMemory
ZeroMemory  FillMemory    StrBufSize

StrAlloc 核心優勢

  • 自動添加 4 字節管理頭:記錄字符串長度 (兼容 Delphi 長字符串格式)
  • 配套函數完整:StrDispose 釋放,StrBufSize 獲取大小
  • 自動選擇編碼:參數為 PWideChar 調用 WideStrAlloc,PAnsiChar 調用 AnsiStrAlloc
  • API 交互完美兼容:以 #0 結尾,帶長度前綴

標準用法:API 緩衝區

var
  p: PChar;
begin
  p := StrAlloc(256);              // 分配 256 字符 (含管理頭)
  try
    GetWindowText(Handle, p, StrBufSize(p));  // 獲取標題
    ShowMessage(p);                // 顯示
  finally
    StrDispose(p);                 // 正確釋放 (含管理頭)
  end;
end;

為什麼不用 FreeMem? 會少釋放 4 字節管理頭,導致內存洩漏。

字符指針分配的其他場景

1. 固定數組作緩衝區 (最簡單、無需釋放)

var
  buf: array[0..MAX_PATH] of Char;
begin
  GetWindowsDirectory(buf, Length(buf));
  ShowMessage(buf);  // C:\Windows
end;
  • 棧分配,函數返回自動釋放
  • 適用於已知最大長度 (如 MAX_PATH=260)

2. 直接賦常量 (系統自動分配)

var p: PChar;
begin
  p := '萬一的 Delphi 博客';  // 編譯器生成常量段數據
  ShowMessage(p);             // 直接使用,無需分配/釋放
end;

3. 手動構造空字符串 (繁瑣)

var p: PChar;
begin
  p := PChar(StringOfChar(#0, 256));  // 256 個 #0
  GetSystemDirectory(p, StrBufSize(p));
  ShowMessage(p);  // C:\Windows\system32
end;

4. API 輸入參數 (無需分配)

// 直接常量
SetWindowText(Handle, '新標題');

// 變量轉型
var str: string;
begin
  str := '萬一的 Delphi 博客';
  TextOut(Canvas.Handle, 10, 10, PChar(str), Length(str));
end;

相關函數對比

StrNew 複製演示

var p1, p2: PChar;
begin
  p1 := 'Delphi';
  p2 := StrNew(p1);      // 分配新內存並複製
  ShowMessageFmt('%s, %s', [p1, p2]); // Delphi, Delphi
  
  p1 := '2009';          // 修改 p1 指向新常量
  ShowMessageFmt('%s, %s', [p1, p2]); // 2009, Delphi (p2 不變)
  
  StrDispose(p2);        // 僅釋放 p2 自己的內存
end;

等效簡化:p2 := p1 直接共享,無需複製 (常量壽命全程有效)。

GlobalAllocPtr / GlobalFreePtr:跨進程共享內存

  • 封裝 GlobalAlloc(GMEM_MOVEABLE/GMEM_FIXED) / GlobalFree
  • 分配全局堆內存,可跨進程邊界共享 (DLL、剪貼板、OLE、共享內存)
  • 參數/返回為 Pointer (無類型),不限於字符指針
  • 後續專題詳細講解

核心原則總結

  1. API 輸出緩衝區:StrAlloc / StrDispose / StrBufSize (首選)
  2. 已知最大長度:固定數組 array[0..N] of Char (最簡單)
  3. 常量輸入:直接賦值,編譯器自動管理
  4. 變量輸入:PChar(str) 轉型即可
  5. 跨進程/模塊:GlobalAllocPtr / GlobalFreePtr
  6. 手動分配必須手動釋放:誰分配誰負責釋放,配對使用

StrAlloc 系列是 Delphi 字符串內存管理的基石,理解其「管理頭」設計,能避免大量內存洩漏與崩潰Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函數用途備註
StrAlloc分配字符串緩衝區 (含管理頭)首選,自動識別寬/窄字符
WideStrAlloc顯式分配寬字符緩衝區StrAlloc(PWideChar) 內部調用
AnsiStrAlloc顯式分配 ANSI 字符緩衝區StrAlloc(PAnsiChar) 內部調用
StrDispose釋放 StrAlloc 分配的內存必須配對使用
StrBufSize獲取緩衝區可用大小 (扣除管理頭)傳給 API 的長度參數
StrNew複製字符指針 (分配新內存)少用,直接賦值 p2 := p1 共享更簡單
NewStr/DisposeStr已棄用 (deprecated)兼容舊代碼,用 @str 獲取指針