马上能想到的函数有:


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();
  GetWindowText(Handle, p, StrBufSize(p));
  ShowMessage(p); {Form1}
  StrDispose(p);
end;

StrAlloc 根据不同的参数(PWideChar、PAnsiChar)分别重载调用了 WideStrAlloc、AnsiStrAlloc, 所以我们也可以直接使用这两个函数(这也需要用 StrDispose 释放), 不过使用它们的必要性不大; 用 StrAlloc 指定好参数类型即可.

给字符指针分配内存其他方法也挺方便, 譬如:


//获取 WINDOWS 所在目录
var
  buf: array[..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(), )); {反复一个空字符 256 次成一个字符串, 然后转为 PChar}
  GetSystemDirectory(p, StrBufSize(p));
  ShowMessage(p); {C:\WINDOWS\system32}
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, , , 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)分配内存, 当然就不仅仅用于字符指针了. 还是到后面专题再做例子吧.

Delphi 的内存操作函数(1): 给字符指针分配内存的更多相关文章

  1. Delphi 的内存操作函数(1): 给字符指针分配内存( 给字符指针(PChar、PWideChar、PAnsiChar)分配内存最佳的选择是StrAlloc。分配内存的时候会对字符串进行初始化)

    马上能想到的函数有: GetMem AllocMem ReallocMem FreeMem GetMemory ReallocMemory FreeMemory New Dispose NewStr ...

  2. Delphi 的内存操作函数(2): 给数组指针分配内存

    静态数组, 在声明时就分配好内存了, 譬如: var   arr1: ..] of Char;   arr2: ..] of Integer; begin   ShowMessageFmt('数组大小 ...

  3. delphi 给字符指针分配内存

    今天,对接第三方dll的时候出现如下问题: 接口声明如下: long BL_tradeBalance (char *MerchantNumber,char *PosId,char *OperatorN ...

  4. Delphi中复制带有String的记录结构时不能使用Move之类的内存操作函数

    请看下面的代码: program TestRecord; {$APPTYPE CONSOLE} uses  SysUtils,  Math; type  TRecordA = record    Na ...

  5. 内存操作函数memmove,memcpy,memset

    通过字符串的学习,我们知道字符串操作函数的操作对象是字符串,并且它的结束标志是结束符\0,当然这个说的是不 受限制的字符串函数.然而当我们想要将一段内存的数据复制到另一块内存时,我们不能使用字符串操作 ...

  6. C语言中内存操作函数

      一.malloc/calloc 名称: Malloc/calloc 功能: 动态内存分配函数 头文件: #include <stdlib.h> 函数原形: void *malloc(s ...

  7. c++ void,内存操作函数

    void的含义 void的字面意思是“无类型”, void * 则为“无类型指针”, void * 可以指向任何类型的数据 void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变 ...

  8. c#读写共享内存操作函数封装

    原文 c#读写共享内存操作函数封装 c#共享内存操作相对c++共享内存操作来说原理是一样,但是c#会显得有点复杂. 现把昨天封装的读写共享内存封装的函数记录下来,一方面希望给需要这块的有点帮助,另一方 ...

  9. 【转】C内存操作函数

    一.malloc/calloc 名称: Malloc/calloc 功能:  动态内存分配函数 头文件: #include <stdlib.h> 函数原形: void *malloc(si ...

随机推荐

  1. xadmin下设置“use_bootswatch = True”无效的解决办法

    环境: python 2.7 django 1.9 xadmin采用源代码的方式引入到项目中 问题: 在xadmin使用的过程中,设置“use_bootswatch = True”,企图调出主题菜单, ...

  2. CSS3-::selection

    “::selection”只能设置两个属性,一个就是background,另一个就是color属性,设置其他属性是没有任何效果的. ::selection使用语法: /*Webkit,Opera9.5 ...

  3. 【php】类型转换

    $a = 9; print_r((array) $a) ; 输出: [0=>9] print_r((array) null); 输出: []

  4. Python从文件中读取数据

    一.读取整个文件内容 在读取文件之前,我们先创建一个文本文件resource.txt作为源文件. resource.txt my name is joker, I am 18 years old, H ...

  5. 初识Pyhon之准备环境

    安装成功python的运行环境之后,你可能要迫不及待大展身手了 如果你有一定的语言基础,那么基础这一块儿就可以简单的看看就可以了,但是你是一个编程语言的初学者.不着急,慢慢往下看 打开pycharm创 ...

  6. DocView mode 0 -- 介绍

          DocView mode,可作为主模式也可以作为minor mode,可以用来阅读DVI(ps后缀),PDF,OpenDocument(libreoffice文档),微软的doc.支持截取 ...

  7. Knockout v3.4.0 中文版教程-6-计算监控-可写的计算监控

    2.可写的计算监控 初学者可能想要跳过本节 - 可写的计算监控是相当高级的部分,在大多数情况下不是必需的. 通常,计算监控是一个通过其他监控值计算出的值,因此是只读的. 令人惊讶的是,可以使计算监控值 ...

  8. JSP标签:jsp内置标签、jstl标签、自定义标签

     一.jsp标签的分类: 1)内置标签(动作标签): 不需要在jsp页面导入标签 2)jstl标签: 需要在jsp页面中导入标签 3)自定义标签 : 开发者自行定义,需要在jsp页面导入标签    1 ...

  9. POJ 1056 IMMEDIATE DECODABILITY

    IMMEDIATE DECODABILITY Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9630   Accepted: ...

  10. linux移动硬盘unmount报错处理

    备份数据用的移动硬盘unmount时报: 通过fuser命令来kill掉设备进程,再unmount移动设备 先看fuser命令帮助信息: [root@athenadb2 ~]# fuser -help ...