查看: 220|回复: 0
打印 上一主题 下一主题

pascal的内存操作函数(1): 给字符指针分配内存

[复制链接] qrcode

28

主题

33

帖子

98

积分

注册会员

Rank: 2

积分
98
楼主
跳转到指定楼层
发表于 2016-2-29 09:35 PM | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
马上能想到的函数有:
GetMem
AllocMem
ReallocMem
FreeMem

GetMemory
ReallocMemory
FreeMemory

New
Dispose

NewStr
DisposeStr

StrNew
StrAlloc
StrDispose

GlobalAllocPtr
GlobalFreePtr

WideStrAlloc
AnsiStrAlloc
StrDispose

Move
MoveMemory
CopyMemory
ZeroMemory
FillMemory
FillChar

StrBufSize


给字符指针(PChar、PWideChar、PAnsiChar)分配内存, 最佳选择是: StrAlloc.
StrAlloc 虽然最终也是调用了 GetMem, 但 StrAlloc 会在指针前面添加 Delphi 需要的 4 个管理字节(记录长度).
StrAlloc 分配的内存, 用 StrDispose 释放, 用 StrBufSize 获取大小.
用 FreeMem 释放可以吗? 这样会少释放 4 个字节.
这种类型的指针一般用于 API 函数的参数, 譬如获取窗口标题:
var   p: PChar; begin   p := StrAlloc(256);
  GetWindowText(Handle, p, StrBufSize(p));
  ShowMessage(p); {Form1}   StrDispose(p); end;


StrAlloc 根据不同的参数(PWideChar、PAnsiChar)分别重载调用了 WideStrAlloc、AnsiStrAlloc, 所以我们也可以直接使用这两个函数(这也需要用 StrDispose 释放), 不过使用它们的必要性不大; 用 StrAlloc 指定好参数类型即可.
给字符指针分配内存其他方法也挺方便, 譬如:
//获取 WINDOWS 所在目录 var   buf: array[0..MAX_PATH] of Char; begin   GetWindowsDirectory(buf, Length(buf));
  ShowMessage(buf); {C:WINDOWS} end;


数组的内存不是我们自己申请的, 系统会自动释放; 记住: 只要是手动申请的内存一定要手动释放.
我们给字符指针申请内存主要是为了在 API 中接受数据, 如果我们要直接赋给常量值, 系统会自动分配内存的, 譬如:
var   p: PChar; begin   p := \'万一的 Delphi 博客\';
  ShowMessage(p); {万一的 Delphi 博客} end;


当然我们也可以用这种办法申请内存, 就是笨了点, 譬如:
//获取系统目录 var   p: PChar; begin   p := PChar(StringOfChar(Char(0), 256)); {反复一个空字符 256 次成一个字符串, 然后转为 PChar}   GetSystemDirectory(p, StrBufSize(p));
  ShowMessage(p); {C:WINDOWSsystem32} end;


如果在 API 函数需要的字符指针是为了输入, 当然也不需要申请内存, 譬如:
//设置窗口标题 var   p: PChar; begin   p := \'窗口新标题\';
  SetWindowText(Handle, p); end; //也可以直接给常量 begin   MessageBox(Handle, \'提示信息\', \'标题\', MB_OK); end; //如果是给字符串的变量或常量, 则需要转换一下 var   str: string; begin   str := \'万一的 Delphi 博客\';
  TextOut(Canvas.Handle, 10, 10, PChar(str), Length(str));
  {在窗体上输出文字, 此代码不能在 OnCreate 事件中} end;


跑题了...到现在已用到了 StrAlloc、StrDispose、WideStrAlloc、AnsiStrAlloc、StrBufSize 几个函数.
还有 NewStr、DisposeStr、StrNew、StrDispose 也貌似有点关系.
先说 NewStr 和 DisposeStr(它们是一对);
NewStr 是根据 AnsiString 再新建一个 PAnsiString, 不过这是为兼容而存在的, Delphi 已不提倡使用了.
不再提倡使用的函数都缀以 deprecated 标识, 并在代码提示中用灰色显示.
其实用 @ 即可获取字符串指针, 当然根本用不着它们.
还有个 StrNew; StrNew 可以再制一个相同的字符指针, 譬如:
var   p1,p2: PChar; begin   p1 := \'Delphi\';

  p2 := StrNew(p1);
  ShowMessageFmt(\'%s, %s\', [p1, p2]); {Delphi, Delphi}   p1 := \'2009\';
  ShowMessageFmt(\'%s, %s\', [p1, p2]); {2009, Delphi}   StrDispose(p2); {释放自己申请的} end;


不过 StrNew 存在的意义也不大, 我们可以更简单地完成上面的操作:
var   p1,p2: PChar; begin   p1 := \'Delphi\';
  p2 := p1;
  ShowMessageFmt(\'%s, %s\', [p1, p2]); {Delphi, Delphi}   p1 := \'2009\';
  ShowMessageFmt(\'%s, %s\', [p1, p2]); {2009, Delphi} end;


说来说去, 好像只有 StrAlloc 是我们值得我们记忆的?
还有一对非常重要的相关函数: GlobalAllocPtr、GlobalFreePtr; 它们的功能是上面这些都不可替代的!

GlobalAllocPtr 和 GlobalFreePtr 是对系统函数: GlobalAlloc、GlobalFree 的简化, 之所以说它们重要, 只是因为它们可以跨进程操作; 不过 GlobalAllocPtr 是给无类型指针(Pointer)分配内存, 当然就不仅仅用于字符指针了. 还是到后面专题再做例子吧. 


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表