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. Hashmap jdk7 死循环

    如果理解的有问题,欢迎大家指正. https://www.cnblogs.com/webglcn/p/10587708.html jdk7的hashmap 由数组和链表组成,存在几个问题: 当key的 ...

  2. PHP 合理配置实现文件上传及保存文件到数据库

    合理配置 php.ini 如何配置php.ini实现PHP文件上传功能.其中涉及到php.ini配置文件中的upload_tmp_dir.upload_max_filesize.post_max_si ...

  3. CentOS 7安装Gitlab时报错:undefined method `downcase' for nil:NilClass

    说明:其实这事怪我,我把系统的某些配置改了. 首先分析这个错误出现的位置在这个文件: /opt/gitlab/embedded/cookbooks/cache/cookbooks/package/li ...

  4. OpenVPN的ipp.txt为空不生效的问题

    1.ipp.txt是分配固定IP使用的,但在tun模式下里面的ip地址不是写使用着的IP,而是30位子网中没有列举出来的启动一位,比如我要给客户机分配为10.8.0.6的IP,那么它这个文件填写的是1 ...

  5. 正余弦信号的DFT频谱分析

    一般的,对正余弦信号进行採样并DFT运算,画出频谱图,会发现频谱并不干净.这样的现象称为频谱泄漏.由于DFT运算仅仅能是有限序列,突然的截断产生了泄漏. 会有这种特殊情况.当採样截取的刚好是整数个周期 ...

  6. Codeforces 235E. Number Challenge DP

    dp(a,b,c,p) = sigma ( dp(a/p^i,b/p^j,c/p^k) * ( 1+i+j+k) ) 表示用小于等于p的素数去分解的结果有多少个 E. Number Challenge ...

  7. USB2.0 速度识别--区分低速-高速-全速

    USB2.0是向下兼容USB1.X的,即USB2.0支持高速,全速,低速的USB设备 (HIGH-SPEED,FULL-SPEED,LOW-SPEED),而USB1.X不支持高速设备. 因此如果高速设 ...

  8. Golang 处理 Json(二):解码

    golang 编码 json 还比较简单,而解析 json 则非常蛋疼.不像 PHP 一句 json_decode() 就能搞定.之前项目开发中,为了兼容不同客户端的需求,请求的 content-ty ...

  9. JavaScript学习总结(二十)——Javascript非构造函数的继承

    一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese = { nation:'中国' }; 还有一个对象,叫做&qu ...

  10. C#编程(三十四)----------数组作为参数

    原文链接: http://blog.csdn.net/shanyongxu/article/details/46765267 数组作为参数 数组可以作为参数传递给方法,也可以从方法中返回.要返回一个数 ...