请问返回值为pchar的函数应该怎样写?(100分)

  • 主题发起人 主题发起人 sadj
  • 开始时间 开始时间
S

sadj

Unregistered / Unconfirmed
GUEST, unregistred user!
比如下面的东西
function ReturnPChar(s: string): Pchar;
var
Value: string;
begin
... ...
Value := ....;
... ...
//这里该怎么将Value返回,首先肯定不是Result := Pchar(Value)
end;
 
你可以定义为function ReturnPChar(s: string): string;啊~

等调用函数时用 aa := Pchar(ReturnPChar(s: string)) //此时用Pchar()
 
为什么要返回PChar,
这样你得自己管理内存,得知道大小,不支持这么做
返回String,再转换成PChar不行吗?
 
一般不会使用PChar作为函数返回值,因为这样你很难保证PChar使用的内存不被释放
String和PChar其实是一样的内存构造,都是以chr(0)结尾,String由于是自动内存分
配,所以效率会高一些,如果你非要转换,可以向下面那样使用


var
pc : PChar;
...
GetMem(pc, strLen(Value) + 1);
StrCopy(pc, PChar(Value));
...
FreeMem(pc)
 
当然是特殊情况啦,不然谁去用那个该死的pchar。[:(]
动态链接dll文件,如果需要让别的语言写程序调用,使用pchar是个比较好的方法,我也不
想用那个sharemem.dll,所以主要还是考虑和其他的程序兼容。返回string不是我所需要的。
 
我目前是这样写的
function StrToPChar(Value: string): PChar;
var
i, l: integer;
r: PChar;
begin
l := Length(Value);
GetMem(r, l + 1);
try
for i := 0 to l - 1 do
begin
r := Value[i + 1];
end;
r[l] := #0;
Result := r;
finally
FreeMem(r, l + 1);
end;
end;
但是我担心FreeMem会将r释放掉,这样Result返回的的值就不可靠,虽然我跟踪了一下,
没有发现变化,但是还是不放心,因为我以前写的一个直接Result := Pchar(VAlue)的,
在一些情况下就无法得出正确的值
 
我的程序都是直接用PChar(TheString)来转换的,没有问题,所以写成:
Result:=PChar(Value);
是没有问题的。
 
to:zqw0117
我看你的程序都要改了。
delphi的文档专门说明了不能使用Result := Pchar(s);
因为s在函数返回的时候将被free掉,而pchar是指针,因此这样做是危险的,如果那个函数区域被覆盖了,
获得的就是一个错误的值。我就是这样错了之后才知道的。
 
我看你的程序也比较危险,我建议使用参数的形式来传递PChar值,这样我觉得安全的多
procedure(var pc: PChar)
 
请问安全在哪里?
这样的话我甚至可以改变pc的内容,即传入函数的pc可以在函数内部被指向另外的内存块,
而如果我们用pc^的话,同样也是可以访问指针所指向的内存块的值。
 
一个不成文的原则是:内存在哪里申请,在哪里释放.看看win32 api 的设计就知道了.如果返回
pchar的话,除非是你自己模块内部的函数,不给别人调用的,否则使用你这个函数的人很难明白
该什么时候去释放这块内存.

同意DragonPC_???的说法,不过参数形式可以是:
procedure(const buff :PChar,const bufflen:Word)
多加一个bufflen参数,供函数内部做验证用.
 
to:darkiss
那么我现在这种情况下:需要编写动态链接dll文件,让其他的语言调用,其他语言使用
并且不想改动函数接口,怎么处理这个问题比较好?函数的格式是
function fn: PChar
stdcall;
 
我写了一个简单的例子,主要是对调用者的要求提高了,需要调用者来管理释放内存.
function callee:PChar
var yourstr:string
// which one you want return it's content to caller
begin
yourstr := 'God it is too bad'
try
GetMem(result,length(yourstr)+1)
except
result := nil
end

if assigned(result) then begin
StrPLCopy(result,yourstr,length(yourstr))
result[length(yourstr)] := #0;
end
end
procedure caller;
var pc :PChar
begin
pc := callee
showmessage(pc)
FreeMem(pc)
// you MUST free the memory that callee allocated
end;
 
result:=pchar(value);

外部使用的时候
要按照pchar的方法来用了!
 
to darkiss
其实我正是在这个问题上烦恼,因为调用的程序已经写好了,变更起来麻烦,所以
我不能指望在后面调用freemem,你看我面的那个写在汉书里面就是这个意思。但是
如果在函数里面释放我担心有可能不能得到正确的内容。
另外请教一个问题,我对函数作了跟踪,发现
代码:
  ...
  finally
    FreeMem(r, l + 1);
  end;
  ...
freemem之后,r指向地址还是存在原来的那字符,请问,到底在什么时候,那块内存
地址被回收呢?

to 徐永进
你的方法不行,楼上已经提到了。
Delphi帮助,主题:Returning a PChar local variable中写道:
A common error when working with PChars is to store in a data structure,
or return as a value, a local variable. When your routine ends, the PChar
will disappear because it is simply a pointer to memory, and is not a reference
counted copy of the string. For example:
代码:
function title(n: Integer): PChar;
var
	s: string;
begin
	s := Format('title - %d', [n]);
	Result := PChar(s)
[red]// DON'T DO THIS[/red]
end;
This example returns a pointer to string data that is freed when the title
function returns.
 
不如这样啊~ 把要返回得到的pchar值放进参数部分 返回值设为boolean 型

再取这个函数参数部分的pchar值啊~
 
to bowl
pchar是指针,这里的问题关键在于如何释放pchar所指向的内存空间。
而又不影响正常的调用。所以即使改变了pchar所指向的地址,但是仍然不能释放内存。
 
free是标记指针指向的内存空间现在处于可用状态,并不是对指针本身的值做任何的改变.

如果你的函数用在对内存空间要求很低(有很大内存)的程序上,或者程序执行的时间不长(在
程序执行的时候有足够的内存可用,不会消耗光),而且是单线程的(不会并发访问),那么简单
的解决方案是在unit中
var AList :TList
nCounter :Integer

.....
procedure XGetMem(var p:Pointer;size:Integer)
begin
GetMem(p,size)
aList.Add(p)

end;


....
function callee:PChar
var yourstr:string
// which one you want return it's content to caller
begin
yourstr := 'God it is too bad'
try
XGetMem(result,length(yourstr)+1)
// use XGetMem instead of default one
except
result := nil
end

if assigned(result) then begin
StrPLCopy(result,yourstr,length(yourstr))
result[length(yourstr)] := #0;
end
end

....
....
....

initialization
AList:=TList.Create
// corrected it,:)
finalization
while nCounter < AList.Count do
begin
freemem(aList.Items[nCounter])
inc(nCounter)
end;
AList.Clear
AList.Free
end.

这是最傻的方法,呵呵.更好的解法应该和gc(garbage collection)有关了,高性能的gc不是我们
这里能搞清楚的吧.
 
嗯,我觉得你这个思路很好,垃圾回收,呵呵。
另外请教一下gc是怎么回事?我在java中用过gc,但是delphi中的是不是也是这样,和
垃圾回收相关吗?我在think in java看到作者写:delphi也是可以有垃圾收集的,不过
要选择安装,是怎么回事?
 
返回值为PCHAR的函数举例:
function ShortStringAsPchar(var S:ShortString):Pchar;
begin
if Length(S)=Hign(S) thenDec(S[0]);
S[Ord(Length(S))+1]:=#0;
Result:=@S[1];
end;
就这么简单!
 
后退
顶部