博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Delphi 的内存操作函数(2): 给数组指针分配内存
阅读量:4922 次
发布时间:2019-06-11

本文共 4288 字,大约阅读时间需要 14 分钟。

静态数组, 在声明时就分配好内存了, 譬如:


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^ := '万一的 Delphi 博客';  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^ := '万一的 Delphi 博客';  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 类用到的理念.
如果你在心里上接受不了那么大一个数组(其实没事, 一个指针才多大? 我们只使用其指针), 也可以这样:


type  TArr = array[0..0] 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;

这好像又让人费解, 只有一个元素的数组能干什么?
应该这样理解: 仅仅这一个元素就足够指示数据的起始点和数据元素的大小和规律了.
另外的 SysGetMem、SysFreeMem、SysAllocMem、SysReallocMem 四个函数, 应该是上面这些函数的底层实现, 在使用 Delphi 默认内存管理器的情况下, 我们还是不要直接使用它们.

转载于:https://www.cnblogs.com/h2zZhou/p/6649813.html

你可能感兴趣的文章
mysql5.7忘记密码修改方法
查看>>
poj 1251续
查看>>
fmt 包中的函数和方法
查看>>
我所了解的一些路由器对比
查看>>
Yii2的深入学习--入口文件
查看>>
Python 多进程
查看>>
Android-Launcher开发之ShortCut(1)
查看>>
SharePoint 2013 图文开发系列之网站栏
查看>>
Sass Maps的函数
查看>>
Linux常用命令之Tmux
查看>>
ubunt1204安装配置vsftp
查看>>
Swift - UIView,UItableView,Cell设置边框方法
查看>>
jdbctemplate
查看>>
Centos7安装mysql-5.7.19
查看>>
ios中的coredata
查看>>
WPF控件库:文字按钮的封装
查看>>
N1 语法单词
查看>>
[转载]DIV CSS设计时IE6、IE7、FF 与兼容性有关的特性
查看>>
[zz]使用thrift做c++,java和python的相互调用
查看>>
使用debootstrap 命令
查看>>