function Test:pachr;
var
  str: string;
begin
  str := 'Test Char';
  result:=pchar(str); end; 上面的Test函数作为导出函数时候会出现访问野指针,因为str已经被释放了;
方法一:改成全局变量保存的话,可以正常访问到数据
var
DataStore:String;
function Test:pachr;
var
  str: string;
begin
  str := 'Test Char';
  DataStore:=str;
  result:=pchar(DataStore); 
end;

方法二:给字符指针分配内存
function Test:pachr;
var
  str: string;
begin
  str := 'Test Char';

  Result:=StrAlloc(Length(str)+1);

  StrPcopy(Result,str);

end;


以下是万一的博客中关于字符串分配内存
万一的博客 http://www.cnblogs.com/del/archive/2008/11/08/1329543.html

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

马上能想到的函数有:

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)分配内存, 当然就不仅仅用于字符指针了. 还是到后面专题再做例子吧.

												

pchar,pwidechar,pansichar作为返回参数时内存访问错误的更多相关文章

  1. 本地安装apk后直接打开,按下Home键再重新打开,然后按下返回键时页面展示错误的处理方法

    情景: 1.下载apk到手机本地,点击本地apk开始安装 2.安装完成后,一般会有 “完成” 和 “打开” 两个按钮,点击 “完成” 按钮时是没有问题的,不管它 3.点击 “打开” 按钮,进入到首页( ...

  2. springmvc4.3.7中使用RequestBody,传入json参数时,得到错误415 Unsupported Media Type

    在新建一个maven的项目的时候,当时并非springboot项目,是通过xml来配置的项目.在项目中DispatcherServlet的配置文件中配置了annotation-driven的, < ...

  3. taotao服务测试http请求需要返回json时出现406错误处理

    @Test public void doPost() throws Exception { CloseableHttpClient httpClient = HttpClients.createDef ...

  4. Char、AnsiChar、WideChar、PChar、PAnsiChar、PWideChar 的用法

     varc: Char; {Char 类型的取值范围是: #0..#255, 用十六进制表示是: #$0..#$FF}begin{用十进制方式赋值:}c := #65;ShowMessage(c); ...

  5. java运行时内存模式学习

    学习java运行时内存模式: 各区介绍: 方法区(线程共享):用于存放被虚拟机加载的类的元数据:静态变量,常量,以及编译和的代码(字节码),也称为永久代(所有该类的实例被回收,或者此类classLoa ...

  6. JVM运行时内存结构

    原文转载自:http://my.oschina.net/sunchp/blog/369707 1.JVM内存模型 JVM运行时内存=共享内存区+线程内存区 1).共享内存区 共享内存区=持久带+堆 持 ...

  7. [转]JVM运行时内存结构

    [转]http://www.cnblogs.com/dolphin0520/p/3783345.html 目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的 ...

  8. java架构之路-(JVM优化与原理)JVM的运行时内存模型

    还是我们上次的图,我们上次大概讲解了类加载子系统的执行过程,验证,准备,解析,初始化四个过程.还有我们的双亲委派机制. 我们这次来说一下运行时内存模型.上一段小代码. public class Mai ...

  9. MongoDB排序时内存大小限制和创建索引的注意事项!

    线上服务的MongoDB中有一个很大的表,我查询时使用了sort()根据某个字段进行排序,结果报了下面这个错误: [Error] Executor error during find command ...

随机推荐

  1. linux学习笔记-5.用户和组

    1.添加一个tom用户,设置它属于users组,并添加注释信息 分步完成: useradd tom usermod -g users tom usermod -c "hr tom" ...

  2. activiti初学

    公司现有的工作流是比较老的JBPM,用起来不太方便,经常性的流程跑一半就停止不前了.闲暇之余学习下activiti的使用,基本配置如下: 1.创建pom.xml文件所依赖的jar包 <proje ...

  3. [ZOJ3781]Paint the Grid Reloaded

    思路: 先用DFS缩点,然后BFS找出每个点出发能到达的最长路,取$min$. 注意多组数据,初始化一定要仔细,刚开始存边的$e$忘记初始化,一直WA,调了半个晚上. 一开始和网上的题解对拍$T=1$ ...

  4. 工具使用-----Jmeter-脚本的录制

    //转载  http://www.cnblogs.com/fnng/archive/2011/08/20/2147082.html 以下是我自己录制的关于这篇文章的视频,有兴趣的可以下载哦 https ...

  5. Android 获取手机信息,设置权限,申请权限,查询联系人,获取手机定位信息

    Android 获取手机信息,设置权限,申请权限,查询联系人,获取手机定位信息 本文目录: 获取手机信息 设置权限 申请权限 查询联系人 获取手机定位信息 调用高德地图,设置显示2个坐标点的位置,以及 ...

  6. CMSIS-DAP for STLink V2.1 and STLink v2.1 mini adapter

    CMSIS-DAP V1 V2

  7. Keil debugging techniques and alternative printf (SWO function)

    One of the basic needs of the embedded software development through the terminal to output debugging ...

  8. Git 代码更新:git fetch 和 git pull 的区别

    Git 从远程的分支获取最新的版本到本地有这样 2 个命令: 1. git fetch:相当于是从远程获取最新版本到本地,但不会自动 merge git fetch origin master git ...

  9. Android笔记之 网络http通信

    0.在认识HTTP前先认识URL 在我们认识HTTP之前,有必要先弄清楚URL的组成,比如: http://www.******.com/china/index.htm 它的含义例如以下: 1. ht ...

  10. Delphi2010 RTTI + Attribute 简单实现ORM实例

    1.支持ORM,最基础的两个信息是表的信息和字段信息.这两个信息,如果用Attribute 来辅助,代码更简洁和可读性更好.可以把属性名当做真实字段名,也可以将特性里的属性当成真实姓名,再加上字段标题 ...