捐助郴維網
感謝您對郴維網的支持,你的支持將是郴維網持續發展的動力!
二維碼
×
當前位置:郴維網 >基礎知識 > 正文
12 2021.12

Delphi 的內存操作函數(2): 給數組指針分配內存

點擊次數:289 更新時間:2021-12-12 14:54:15  【打印此頁

靜態數組, 在聲明時就分配好內存了, 譬如:

var
  arr1: array[0..255] of Char;
  arr2: array[0..255] of Integer;
begin
  ShowMessageFmt('數組大小分別是: %d、%d', [SizeOf(arr1), SizeOf(arr2)]);
  {數組大小分別是: 512、1024}
end;

對靜態數組指針, 雖然在聲明之處并沒有分配內存, 但這個指針應該分配多少內存是有定數的.

這種情況, 我們應該用 New 和 Dispose 來分配與釋放內存. 譬如:

type
  TArr1 = array[0..255] of Char;
  TArr2 = array[0..255] of Integer;
var
  arr1: ^TArr1;
  arr2: ^TArr2;
begin
  New(arr1);
  New(arr2);

  arr1^ := '郴維網 - 1118pc.com';
  ShowMessageFmt('%s%s', [arr1^[0], arr1^[1]]); {郴維}
// ShowMessageFmt('%s%s', [arr1[0], arr1[1]]); {這樣也可以}

  arr2[Low(arr2^)] := Low(Integer); {第一個元素賦最小值}
  arr2[High(arr2^)] := MaxInt;      {第一個元素賦最大值}
  ShowMessageFmt('%d, %d', [arr2[0], arr2[255]]); {-2147483648, 2147483647}

  Dispose(arr1);
  Dispose(arr2);
end;

// 變通一下, 再做一遍這個例子:
type
  TArr1 = array[0..255] of Char;
  TArr2 = array[0..255] of Integer;
  PArr1 = ^TArr1;
  PArr2 = ^TArr2;
var
  arr1: PArr1;
  arr2: PArr2;
begin
  New(arr1);
  New(arr2);

  arr1^ := '郴維網 - 1118pc.com';
  ShowMessageFmt('%s%s', [arr1[0], arr1[1]]);

  arr2[Low(arr2^)] := Low(Integer);
  arr2[High(arr2^)] := MaxInt;
  ShowMessageFmt('%d, %d', [arr2[0], arr2[255]]); {-2147483648, 2147483647}

  Dispose(arr1);
  Dispose(arr2);
end;

給已知大小的指針分配內存應該用 New, 上面的例子是關于靜態數組指針的, 后面要提到的結構體(記錄)的指針也是如此.

New 的本質也函數調用 GetMem, 但不需要我們指定大小了.

但這對動態數組就不合適了, 不過給動態數組分配內存 SetLength 應該足夠了, 譬如:

var
  arr: array of Integer;
begin
  SetLength(arr, 3);

  arr[0] := Random(100);
  arr[1] := Random(100);
  arr[2] := Random(100);

  ShowMessageFmt('%d,%d,%d', [arr[0],arr[1],arr[2]]); {0,3,86}
end;

那怎么給動態數組的指針分配內存呢? 其實動態數組變量本身就是個指針, 就不要繞來繞去再給它弄指針了.

不過有一個理念還是滿重要的, 那就是我們可以把一個無類型指針轉換為動態數組類型, 譬如:

type
  TArr = array of Integer;
var
  p: Pointer;
begin
  GetMem(p, 3 * SizeOf(Integer)); {分配能容納 3 個 Integer 的空間}

  {這和 3 個元素的 TArr 的大小是一樣的, 但使用時需要進行類型轉換}
  TArr(p)[0] := Random(100);
  TArr(p)[1] := Random(100);
  TArr(p)[2] := Random(100);

  ShowMessageFmt('%d,%d,%d', [TArr(p)[0], TArr(p)[1], TArr(p)[2]]); {0,3,86}

  FreeMem(p);
end;

這里用到了 GetMem 和 FreeMem, 對分配無類型指針這是比較常用的; 對其他類型的指針它可以, 但不見得是最好的方案, 譬如:

// 獲取窗口標題(顯然不如用前面說過的 StrAlloc 更好)
var
  p: Pointer;
begin
  GetMem(p, 256);
  GetWindowText(Handle, p, 256);
  ShowMessage(PChar(p)); {Form1}
  FreeMem(p);
end;

應該提倡用 GetMemory 和 FreeMemory 代替 GetMem、FreeMem, 譬如:

var
  p: Pointer;
begin
  p := GetMemory(256);
  GetWindowText(Handle, p, 256);
  ShowMessage(PChar(p)); {Form1}
  FreeMemory(p);
end;

先總結下:

New 是給已知大小的指針分配內存;

GetMem 主要是給無類型指針分配內存;

盡量使用 GetMemory 來代替 GetMem.

還有個 AllocMem 和它們又有什么區別呢?

AllocMem 分配內存后會同時初始化(為空), GetMem 則不會, 先驗證下:

var
  p1,p2: Pointer;
begin
  p1 := AllocMem(256);
  ShowMessage(PChar(p1)); {這里會顯示為空}
  FreeMemory(p1);

  p2 := GetMemory(256);
  ShowMessage(PChar(p2)); {這里會顯示一些垃圾數據, 內容取決與在分配以前該地址的內容}
  FreeMemory(p2);
end;

關于 FreeMemory 與 FreeMem 的區別:

1、FreeMemory 會檢查是否為 nil 再 FreeMem, 這有點類似: Free 與 Destroy;

2、FreeMem 還有個默認參數可以指定要釋放的內存大小, 不指定就全部釋放(沒必要只釋放一部分吧);

3、New 對應的 Dispose 也可以用 FreeMem 或 FreeMemory 代替.

盡量使用 FreeMemory 來釋放 GetMem、GetMemory、AllocMem、ReallocMem、ReallocMemory 分配的內存.

ReallocMem、ReallocMemory 是在已分配的內存的基礎上重新分配內存, 它倆差不多 ReallocMemory 比 ReallocMem 多一個 nil 判斷, 盡量使用 ReallocMemory 吧. 譬如:

type
  TArr = array[0..MaxListSize] of Char;
  PArr = ^TArr;
var
  arr: PArr;
  i: Integer;
begin
  arr := GetMemory(5);
  for i := 0 to 4 do arr[i] := Chr(65+i);
  ShowMessage(PChar(arr)); {ABCDE}

  arr := ReallocMemory(arr, 26);
  ShowMessage(PChar(arr)); {ABCDE}
  for i := 0 to 25 do arr[i] := Chr(65+i);
  ShowMessage(PChar(arr)); {ABCDEFGHIJKLMNOPQRSTUVWXYZ}
end;

注意上面這個例子中 TArr 類型, 它被定義成一個足夠大的數組; 這種數組留出了足夠的可能性, 但一般不會全部用到.

我們一般只使用這種數組的指針, 否則一初始化將會內存不足而當機.

即便是使用其指針, 也不能用 New 一次行初始化; 應該用 GetMem、GetMemory、AllocMem、ReallocMem、ReallocMemory 等用多少申請多少.

需要注意的是, 重新分配內存也可能是越分越少; 如果越分越大應該可以保證以前數據的存在.

這在 VCL 中 TList 類用到的理念.

如果你在心里上接受不了那么大一個數組(其實沒事, 一個指針才多大? 我們只使用其指針), 也可以這樣:

這好像又讓人費解, 只有一個元素的數組能干什么?

應該這樣理解: 僅僅這一個元素就足夠指示數據的起始點和數據元素的大小和規律了.

另外的 SysGetMem、SysFreeMem、SysAllocMem、SysReallocMem 四個函數, 應該是上面這些函數的底層實現, 在使用 Delphi 默認內存管理器的情況下, 我們還是不要直接使用它們.

Tips
郴維網為您提供各類專業服務:
軟件開發,電腦配件銷售,WIFI路由器銷售,上門電腦維修,上門安裝系統,系統安裝,軟、硬件安裝,電腦除塵清灰,顯示器維修,WIFI安裝調試,服務器維護,數據恢復,密碼破解,網絡布線,網絡檢修,打印機維修,打印機加碳粉,蘋果電腦安裝系統,蘋果電腦安裝雙系統,監控安裝維護,電腦外包,筆記本電腦維修,餐飲、美容行業軟件安裝 等。。。。。。
點擊次數:289 更新時間:2021-12-12 14:54:15  【打印此頁
關鍵詞推薦:郴州電腦城 郴州電腦維修公司 維修電腦公司 郴州軟件開發 上門電腦維修 上門安裝系統 筆記本電腦維修 郴州打印機維修 打印機加碳粉 電腦安裝雙系統 蘋果電腦雙系統 液晶顯示器維修 聯想筆記本維修 聯想筆記本維修電話 戴爾筆記本維修電話 郴州戴爾筆記本維修 戴爾筆記本郴州維修點 華碩筆記本維修點 郴州華碩筆記本維修 郴州筆記本上網維修
免费A级毛片无码A∨免费软件