function Test:pachr;
varstr: string;
beginstr := 'Test Char';result:=pchar(str); 

end;

上面的Test函数作为导出函数时候会出现访问野指针,因为str已经被释放了;
方法一:改成全局变量保存的话,可以正常访问到数据
varDataStore:String;
function Test:pachr;
varstr: string;
beginstr := 'Test Char';
  DataStore:=str;
  result:=pchar(DataStore); 
end;
方法二:给字符指针分配内存
function Test:pachr;
varstr: string;
beginstr := '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
FreeMemGetMemory
ReallocMemory
FreeMemoryNew
DisposeNewStr
DisposeStrStrNew
StrAlloc
StrDisposeGlobalAllocPtr
GlobalFreePtrWideStrAlloc
AnsiStrAlloc
StrDisposeMove
MoveMemory
CopyMemory
ZeroMemory
FillMemory
FillCharStrBufSize

给字符指针(PChar、PWideChar、PAnsiChar)分配内存, 最佳选择是: StrAlloc.

StrAlloc 虽然最终也是调用了 GetMem, 但 StrAlloc 会在指针前面添加 Delphi 需要的 4 个管理字节(记录长度).

StrAlloc 分配的内存, 用 StrDispose 释放, 用 StrBufSize 获取大小.

用 FreeMem 释放可以吗? 这样会少释放 4 个字节.

这种类型的指针一般用于 API 函数的参数, 譬如获取窗口标题:

varp: PChar;
beginp := StrAlloc(256);GetWindowText(Handle, p, StrBufSize(p));ShowMessage(p); {Form1}StrDispose(p);
end;

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

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

//获取 WINDOWS 所在目录
varbuf: array[0..MAX_PATH] of Char;
beginGetWindowsDirectory(buf, Length(buf));ShowMessage(buf); {C:\WINDOWS}
end;

数组的内存不是我们自己申请的, 系统会自动释放; 记住: 只要是手动申请的内存一定要手动释放.

我们给字符指针申请内存主要是为了在 API 中接受数据, 如果我们要直接赋给常量值, 系统会自动分配内存的, 譬如:

varp: PChar;
beginp := '万一的 Delphi 博客';ShowMessage(p); {万一的 Delphi 博客}
end;

当然我们也可以用这种办法申请内存, 就是笨了点, 譬如:

//获取系统目录
varp: PChar;
beginp := PChar(StringOfChar(Char(0), 256)); {反复一个空字符 256 次成一个字符串, 然后转为 PChar}GetSystemDirectory(p, StrBufSize(p));ShowMessage(p); {C:\WINDOWS\system32}
end;

如果在 API 函数需要的字符指针是为了输入, 当然也不需要申请内存, 譬如:

//设置窗口标题
varp: PChar;
beginp := '窗口新标题';SetWindowText(Handle, p);
end;//也可以直接给常量
beginMessageBox(Handle, '提示信息', '标题', MB_OK);
end;//如果是给字符串的变量或常量, 则需要转换一下
varstr: string;
beginstr := '万一的 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 可以再制一个相同的字符指针, 譬如:

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

不过 StrNew 存在的意义也不大, 我们可以更简单地完成上面的操作:

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

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

pchar,pwidechar,pansichar作为返回参数时内存访问错误相关推荐

  1. 驱动开发:蓝屏BSOD 0x3B 内存访问错误

    寻找错误的原因每次都是漫长而艰辛的 这次的0x3B错误是内存访问错误,通过windbg我们很容易定位到了错误语句 LONG search(UNICODE_STRING input) {if (path ...

  2. 内存访问错误造成Segmentation fault (SIGSEGV)

    linux下程序对SIGSEGV信号的默认处理方式是产生coredump并终止程序,可以参考man 7 signal Signal     Value     Action   Comment ─── ...

  3. linux SIGSEGV信号 内存访问错误 Segmentation fault

    linux下程序对SIGSEGV信号的默认处理方式是产生coredump并终止程序,可以参考man 7 signal Signal     Value     Action   Comment ─── ...

  4. 存储过程传递参数时出现类型转换错误!如:varchar转换为int时出错

    碰到过这个问题:当时的程序大致如下: create procedure myproc @tablename varchar(20), @idnum int as declare @sqlstr var ...

  5. c语言运行时内存不够,浅析C语言运行时内存管理

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 主要讨论C语言怎样组织正在运行的程序的数据结构的细节. 我们知道知道在UNIX操作系统中,一个C语言文件经过预处理(cp ...

  6. 运行时错误7内存溢出_JVM运行时内存数据区域

    阅读本文大概需要5分钟 作者:AI乔治出处:https://my.oschina.net/u/3611782/blog/4530512 1 讨论背景 周志明老师写的<深入理解Java虚拟机> ...

  7. JVM内存参数设置及常见错误总结

    一.  JVM规范 JVM规范对Java运行时的内存划定了几块区域(详见这里),有:JVM栈(Java Virtual Machine Stacks).堆(Heap).方法区(Method Area) ...

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

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

  9. 深入理解java虚拟机一 JAVA运行时内存区域与class文件

    一 JAVA运行时内存区域 JVM在加载class文件时,会将class文件定义的数据结构转为运行时内存中的数据,那么jvm是如何安排运行时的内存区域呢? jvm将运行时内存划分为以下几个部分: 堆: ...

最新文章

  1. 电容和频率的关系_为什么会有直流电和交流电?频率为什么是50hz?白话科普专业知识...
  2. python pycharm 如何绘制类图 关系图 继承图 父子图?
  3. 使用Maven和WebLogic 12c开发Java EE应用程序
  4. 判断1000-2000之间的闰年(优化写法)
  5. 用js实现图片的无缝滚动效果
  6. Javascript第六章JavaScript中构造器创建对象第二课
  7. Dynamic programming
  8. [android]实现拖动效果
  9. wpf 让图标显示在系统托盘
  10. 良心安利陶瓷材质贴图素材网站
  11. 屏幕录像专家注册机破解方法
  12. 程序员面试智力题总结
  13. SPSSPRO杯第十五届数学中国数学建模网络挑战赛赛题浅评
  14. C# EXCEL 删除行
  15. php爬取html内容,php抓取网页html,curl和file_get_contents通过get或post方式抓取网页内容,源代码
  16. Interval数据类型
  17. netconf协议开发
  18. C++11新特性(侯捷)——课程笔记(九)
  19. 《The One!团队》第八次作业:ALPHA冲刺(四)
  20. 使用org.apache.pdfbox 2.x PDF 转Doc 转图片 转字符串

热门文章

  1. Ubuntu系统查看mongo得慢日志,及一些操作
  2. POJ 3320 尺取法,Hash,map标记
  3. 关于输入输出流的心得
  4. 格式化显示在Label控件中的金额格式文本 (2)
  5. javascript 运算+
  6. ArcGIS中标注之一上下标、分数等特殊形式标注(转)
  7. java的类型默认存储类型_java 问题:保存对话框的默认文件类型?
  8. java面试题 多线程_Java面试常见关于多线程的面试题
  9. Java加载词向量_W2C得到词向量之后,如何得到句子向量,
  10. svn无法读取日志问题解决