因为需要Pchar作为返回值,所以把一个函数f1封装成f2,如下。完全确定f1的返回值是正确的,调用任何多次不会出现问题。但是连续多次调用f2,会在部分次数里出现返回值错误,继续调用多次,程序会报错。
function f1():TStringList;
begin
......
end;
function f2(var OutPut:Pchar):integer;
var StrL:TStringList;
begin
StrL:=f1();
Result:=StrL.Strings[0];
OutPut:=Pchar(StrL.Text);
end;
报错情况:
Project xxxx raised exception class EAccessViolation with message ' Access violation at address 0040446f in module 'xxxx'.Read of address oode8484'.Process stopped. Use Step or Run to continue.问题出在Pchar()这里。有谁碰到过类似的情况?原因是什么?是否Pchar指向的地址在f2结束的时候就已经无效了?如何解决?
function f1():TStringList;
begin
......
end;
function f2(var OutPut:Pchar):integer;
var StrL:TStringList;
begin
StrL:=f1();
Result:=StrL.Strings[0];
OutPut:=Pchar(StrL.Text);
end;
报错情况:
Project xxxx raised exception class EAccessViolation with message ' Access violation at address 0040446f in module 'xxxx'.Read of address oode8484'.Process stopped. Use Step or Run to continue.问题出在Pchar()这里。有谁碰到过类似的情况?原因是什么?是否Pchar指向的地址在f2结束的时候就已经无效了?如何解决?
function f2(var OutPut:Pchar):integer;
var StrL:TStringList;
begin
StrL:=TStringList.Create;
StrL:=f1();
Result:=StrL.Strings[0];
OutPut:=Pchar(StrL.Text);
StrL.Destroy;
end;
begin
......
end;
function f2(var OutPut:Pchar):integer;
var StrL:TStringList;
begin
StrL:=TStringList.Create;
if not f1(StrL) then
begin
showmessage('result error');
result := -1;
exit;
end;
Result:=StrL.Strings[0];
OutPut:=Pchar(StrL.Text);
StrL.Destroy;
end;
begin
//Result.String[0]在-1的时候表示result error
//f1做测试,不存在问题
......
end;
function f2(Str:Pchar;var OutPut:Pchar):integer;
var StrL:TStringList;
begin
//Result在-1的时候表示result error
StrL:=TStringList.Create;
StrL:=f1(StrPas(Str));
Result:=StrL.Strings[0];
OutPut:=Pchar(StrL.Text);
StrL.Destroy;end;
也不知道是怎样通过编译的。如果StrL没有内容,就会发生ListIndexOutOfRange异常。代码很混乱。你的f2之所以在返回时得到一个无效的Output是因为,PChar转换是不会增加字符串的引用计数的,f2返回的时候Output指向的字符串已经在end语句之前释放了。如果f2的Output声明为string类型相对来说比较方便,否则你要在f2函数体内在堆中分配存放Output的内容的空间,然后在f2函数体外释放它,如果扯到DLL,那就更麻烦了。按照pazze大佬的一贯说法,换个思路。
begin
//Result.String[0]在-1的时候表示result error
//f1做测试,不存在问题
......
end;
function f2(Str, OutPut:Pchar):integer;
var StrL:TStringList;
begin
//Result在-1的时候表示result error
//StrL:=TStringList.Create;
StrL:=f1(StrPas(Str));
Result:=StrL.Strings[0];
//OutPut:=Pchar(StrL.Text);
StrPCopy(OutPut, StrL.Text);
//StrL.Destroy;
StrL.Free;
end;在调用f2之前对应OutPut参数PChar变量要先分配内存。记得使用完后释放。
function f2(Str:Pchar;var OutPut:Pchar):integer;
和
function f2(Str:Pchar;OutPut:Pchar):integer;
差着一个Var呢!看明白再说我没分配空间成吗?
成function f2(Str, OutPut:Pchar):integer;这样因为可以使分配空间和释放空间在同一个函数内进行。这是一种好的编程规范。对于PChar变量指针。指针变量它的值是地址,对于这种变量不需要使用Var,除非你想在调用函数内给PChar变量分配地址。
你声明的integer,却在过程中给他字符型。
下面是我测试的结果:
代码:
******
function TForm1.f1: tstringlist;
begin
result:=tstringlist.Create;
result.Add('2222222');
result.Add('ssss');
end;function TForm1.f2(var output:pchar):integer;
var StrL:TStringList;
begin
//Result在-1的时候表示result error
StrL:=TStringList.Create;
StrL:=f1;
Result:=strtoint(StrL.Strings[0]);
OutPut:=Pchar(StrL.Text);
StrL.Destroy;end;procedure TForm1.Button1Click(Sender: TObject);
var st:pchar;
i:integer;
begin
for i:=0 to 50 do
f2(st);
end;
*********
结果:50遍没有错误怪现象?????
1. 你的f2其实调用了两次TStringList.Create,而只调用了一次TStringList.Destroy;
2. 你在Button1Click中光调用f2而不存取st当然看不到异常啦。to musicdog(白狮子):
你别扁我!就当我没说过。
'17
i
ii
iii
iv
v
vi
一
二
三
四
五
六
七
八
九
十
十一
'
开始40多次都对,后来有的时候长(加了多余的字符),有的时候短。
你把你的的output输出看一下,每次都对吗?我也去试试。
3遍以后的结果是
**** 第4遍*****
222222
ssss****第5遍******
222222
ssss少了一个???
但在内存中strl.text的值是'2222222'#$D#$A'ssss'#$D#$A
还是4个s!!!!!!!!!!!
困惑中......
另外我也同意: zuoyexingchen(昨夜星尘)的看法,Pchar类型,无所谓Var的,都是地址,本也是一直这么的用过来的,而且是在Dll中最常用到。
凭经验你差远了,大家的已经都是凭自己的积累而论的,你不但没有把自己的问题讨论好,反而让人觉得很没有意思。
=>
getmem(output,length(strl.text);
strpcopy(output,strl.text);
var
PList : TStringList;
begin
PList := TStringList.Create;
try
PList.Add('123456');
PList.Add('ABCDEF');
Result := PList;
finally
//PList.Free;
end;
end;function F2(output : pchar) : Integer;
var StrL:TStringList;
begin
//Result := -1;
StrL:=TStringList.Create;
try
StrL:=F1();
Result:=StrToInt(StrL.Strings[0]);
StrPCopy(OutPut, StrL.Text);
finally
StrL.Free;
end;
end;
procedure TForm1.HsBitBtn1Click(Sender: TObject);
var
lRel : integer;
sOutBuffer : string;
begin
SetLength(sOutBuffer, 100);
lRel := F2(PChar(sOutBuffer));
SetLength(sOutBuffer, StrLen(PChar(sOutBuffer)));
Memo1.Lines.Add(IntToStr(lRel) + sOutBuffer);
end;到底谁菜,自己明白了吧!无聊!可以试吗?你真的很有个性,无聊分子。
但是我想那些愿意亲自动手尝试的人们不完全是看分数来的。xiaocha(小查)如果愿意,请留下QQ号,Delphi还有好多问题要请教。再次感谢。结帖去。
但是,我发现没办法free得到到内存,不知道会不会造成内存泄漏