program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
ss: string;
p: pchar;
function ShortStringAsPChar(S:ShortString):PChar;
var s1:string;
begin
s1:=s; //将shortstring转换为string
Result:=pchar(s1); {返回PChar化的字符串}
end ;
begin
ss := hello;
p := ShortStringAsPChar(ss);
ss := 1;
ss := 2;
writeln(p);
readln;
end.
请大家先猜一下输出结果再看下面的内容!
==================================================================================
begin
ss := hello;
p := ShortStringAsPChar(ss);
ss := s;
ss := ;
writeln(p);
readln;
end.会是什么输出结果?为什么?
begin
ss := hello;
p := PChar(ss);
ss := 1;
ss := 2;
writeln(p);
readln;
end.会是什么输出结果?为什么?
begin
ss := hello;
p := PChar(ss);
ss := ;
ss := ddd;
writeln(p);
readln;
end.会是什么输出结果?为什么?
前几天我看《Delphi5 开发人员指南》介绍一个ShortStringAsPChar函数,下面为原文([ ]内的):
[
ShortStringAsPChar()函数是在STRUTILS.PAS单元中定义的。
func function ShortStringAsPChar(var S:ShortString):PChar;
{这函数能使一个字符串以null结尾,这样就能传递给需要PChar类型参数的Win32 API函数,如果字符串超过254个字符,多出的部分将被截掉}
begin
if Length(S)=High(S) then Dec(S[0]); {如果S太长,就截取一部分}
S[Ord(Length(S))+1]:=#0; {把null加到字符串的最后}
Result:=@S[1]; {返回PChar化的字符串}
end ;
]
我在使用的时候发现在STRUTILS.PAS这个单元中根本没有这个函数!并且用上面这个函数有可能得到不正确的答案,于是我就写了下面这个函数:
function ShortStringAsPChar(S:ShortString):PChar;
var s1:string;
begin
s1:=s; //将shortstring转换为string
Result:=pchar(s1); {返回PChar化的字符串}
end ;
由于我对delphi的ansistring、pchar、shortstring什么的结构及他们之间的乱七八糟的转换不了解,于是我就写信问一个朋友,让它看看这个函数是否有毛病。他的答复是“ShortStringAsPChar函数有问题,你运行一下上面的代码看看会有什么结果”就是最上面的那段程序了。
我的思路是这样的:
ss为AnsiString型。
ss := hello;时,ss指向hello所在的地址,hello的引用记数为1。
p := ShortStringAsPChar(ss);时,函数ShortStringAsPChar(S:ShortString):PChar;开始执行,
因为参数s为值参,所以AnsiString型的hello(ss的)被复制到一块新的内存中,又因为S为ShortString型,因此要对AnsiString型的hello进行类型转换,所以AnsiString型的hello结构中的大小标记、引用记数及最后面的null都被去掉了,最后,将shortstring型的hello(s的)的地址赋给S 。
s1:=s;时,hello(s的)再次被复制到一块新的内存中并且转换成ansistring类型,最后将地址赋给s1。(hello变为s1的了)
Result:=pchar(s1);时,Result和s1指向同一块内存。然后将其赋给p。(P指向s1的hello)
ss := 1;时,hello(SS的)所在的那块内存被释放, 1被储存在新的内存块中,ss指向 1所在的新地址。
ss := 2;时,1所在的那块内存被释放, 2被储存在新的内存块中,ss指向 2所在的新地址。
writeln(p);时,由于hello(S1的)未受到上面ss重新赋值的影响,所以应输出:hello。
然而,输出的结果却是$
如果将ss := 1;或ss := 2;去掉,则输出为2或1,如果两个都去掉则输出为hello。怪哉!
想了半天突然发现既然是ShortStringAsPChar那么ss就应该是ShortString型,于是将ss声明为
var ss:string[5]; 运行上面的程序,输出结果为hello,不在受ss被重新赋值的影响了。问题看似解决了,可是转念又一想,为什么将ss声明为string类型就不行呢?
我是菜鸟,想了好久也想不出来,只好来请教各位了,希望各位老师不惜赐教!谢谢,谢谢了!我要崩溃了!!!!!!!
最好能给我讲一讲delphi是怎样在这些类型之间进行转换的!
你够细心的,佩服,不过我不清楚,帮你UP,我也希望知道答案!
上面罗里巴索一大堆。。。。
我想应该很简单的。。。
将一个STRING转成PCHAR类型,
你想想会丢掉什么信息?
1,字符长度,这个没有关系,PCHAR空字符结尾。
2,引用计数,这往往是被人忽略的,
当你在一个函数体里使用了STRING,并把它转变成PCHAR类型传出来,
这个过程会发生这样事情:
1,函数体的STRING,它的内存在堆中分配的,这不用担心。
2,一个指针指向这块内存。这也没有问题。
3,函数调用完成,内部使用的string完全使命,就是说没有string类型再引用
那块内存。这块内存被释放。
4,传出去的指针继续指着那块内存,运气好的话,这块释放的内存还比较完好。。。
为了防止没有引用的内存块释放,
三个办法。
一,让它的引用计数加一,
二,还是老实点,用STRING类型把参数传出来。
三,函数内手工分配这个内存,不使用STRING的引用。
楼主的叙述太罗嗦了,没有仔细看——
不过在第一段程序中存在隐患:
函数的参数是S:ShortString为传值参数,而
s1:string是函数内部的局部函数,函数的
返回值又是返回s1的地址pchar(s1),这样返回的
地址不安全,因为s1在函数结束后是释放掉的,
以后这段地址可能做为它用!!
看这个
function GetAddr(I: Integer):pointer;
begin
result := @i;
end;
他们的两个问题是一样的
这就好了:-)
function ShortStringAsPChar(S:ShortString):PChar;
var s1:string;
p1: pchar;
begin
s1:=s;
P1:=StrAlloc(64*SizeOf(Char));
StrPCopy(P1,ss);
Result:=p1;
end ;
StrPCopy(P1,s1);//哈哈。写错了,应该这样
为什么将ss声明为string类型就不行呢?
----------------------------------------------
正如halfdream(哈欠)所说,PChar变量需要人工分配和释放存放字符串的内存。
其实我上面的代码还不完善,还应该将他释放掉,但是因为你想把函数的返回值传出来
所以不能释放,哈哈哈,就交给编译器处理吧
乱七八糟,看不下去。
不过还是帮你up!!!!!!!111