关于强制类型转换后的内存问题,我想知道是否需要释放?
如:
function ShortStringAsPChar(S:ShortString):PChar;
var s1:string;
begin
s1:=s; //将shortstring转换为string
Result:=pchar(s1); {返回PChar化的字符串}
end ;
string类型是生存期自管理的,而pchar不是,那么将string强制转换为pchar类型后是否还需将转换后的变量进行释放?另外看一下这个函数定义的可以吗?
《Delphi5 开发人员指南》上说:
“在练习将一个字符串转换为PChar类型时要小心,因为字符串在超出其作用范围时有自动回收的功能,因此当进行P:=PChar(Str)的赋值时,P的作用域(生存期)应当大于Str的作用域。”
这句话是什么意思?好像是说反了吧?
如:
function ShortStringAsPChar(S:ShortString):PChar;
var s1:string;
begin
s1:=s; //将shortstring转换为string
Result:=pchar(s1); {返回PChar化的字符串}
end ;
string类型是生存期自管理的,而pchar不是,那么将string强制转换为pchar类型后是否还需将转换后的变量进行释放?另外看一下这个函数定义的可以吗?
《Delphi5 开发人员指南》上说:
“在练习将一个字符串转换为PChar类型时要小心,因为字符串在超出其作用范围时有自动回收的功能,因此当进行P:=PChar(Str)的赋值时,P的作用域(生存期)应当大于Str的作用域。”
这句话是什么意思?好像是说反了吧?
解决方案 »
- 求解UDP通信问题。Indy10中的TidUDPClient 与TidUDPServer 通信出错
- 提示“datasource1:circular datalinks are not allowed"这是什么意思?
- 为什么在Delphi7中安装QuickReport时提示无效包dclqrt70.bpl?
- 急,请高手赐教!ADO更新ORACLE数据库的一个问题。
- {$ifdef SEAS_SERVICE}这东西什么意思,容易得分啊 200501
- 很简单的,帮帮忙啊!先谢了!
- 已知一有重复数据的数组,如何把不重复的数据写入另一数组,已放两天了,没人会,高手帮帮忙,
- 跪求大哥大姐施舍我积分!
- 请高手指点 Paradox库怎么存有500汉字的字段
- About FlashForm
- 如何在内存中搜索指定进程中的字符串?
- 很爽的打印dbgrid,stringgrid,datasource.的控件。
var s:string;
p:pchar;
begin
s:='i love you';
p:=pchar(s);
messagebox(handle,p,'',mb_ok);
memo1.Lines.Add('s address:'+inttostr(integer(s)));
memo1.Lines.Add('s[1] address:'+inttostr(integer(@s[1])));
memo1.Lines.Add('s[2] address:'+inttostr(integer(@s[2])));
memo1.Lines.Add('s[3] address:'+inttostr(integer(@s[3])));
memo1.Lines.Add('p address:'+inttostr(integer(p)));
s[1]:='u';
messagebox(handle,p,'',mb_ok);
memo1.Lines.Add('s address:'+inttostr(integer(s)));
memo1.Lines.Add('s[1] address:'+inttostr(integer(@s[1])));
memo1.Lines.Add('s[2] address:'+inttostr(integer(@s[2])));
memo1.Lines.Add('s[3] address:'+inttostr(integer(@s[3])));
memo1.Lines.Add('p address:'+inttostr(integer(p)));end;procedure TForm1.Button2Click(Sender: TObject);
var
st:string;
pt:pchar;
begin
pt:=pchar(strtoint(edit1.Text));
messagebox(handle,pt,'',mb_ok);
end;procedure TForm1.Button3Click(Sender: TObject);
begin
showmessage(chr(pbyte(strtoint(edit1.Text))^));
end;经过我观察,点击按钮button1后,把p的地址写入edit1中点击button2 还能看到'i love you',说明这些字符还在内存中。
代码如下:
var p:PChar;s:string;
begin
s:='abcd';
p:=pChar(s);
Memo1.Lines.Add('Initialized s.');
Memo1.Lines.Add(Format('s'' pointer:%p',[@s[1]]));
Memo1.Lines.Add(Format('p'' pointer:%p',[Pointer(p)]));
MessageBox(handle,p,nil,MB_OK);
Memo1.Lines.Add('s changed.');
s:='cd';
Memo1.Lines.Add(Format('s'' pointer:%p',[@s[1]]));
Memo1.Lines.Add(Format('p'' pointer:%p',[Pointer(p)]));
//这里,p的指针和前面的是一样的,而s的指针却改变了.
MessageBox(handle,p,nil,MB_OK);
Memo1.Lines.Add('one byte of s changed.');
s[1]:='d';
Memo1.Lines.Add(Format('s'' pointer:%p',[@s[1]]));
Memo1.Lines.Add(Format('p'' pointer:%p',[Pointer(p)]));
//这里,p和s的指针都没有改变
MessageBox(handle,p,nil,MB_OK);
FreeMem(p);//产生了一个Invalid Pointer Operation的异常
我想你理解错了。《Delphi5 开发人员指南》上说的是P的作用域(生存期)应当大于Str的作用域而不是字符串长度的问题。我觉得《Delphi5 开发人员指南》上的那句话还是有问题。to: Eastunfail(恶鱼杀手)
我同意“如果修改字符串类型s的值,实际上是释放掉原来的内存并重新分配了内存。”这句话,但是,在你的例子里当p:=pChar(s);后,执行s:='cd';时,我想并没有释放掉原来的内存,因为在p:=pChar(s)时增加了一次对s的引用,s:='cd时只是新开辟了一块内存并将'cd'写入,而没有释放'abcd'所在的内存,如果在s:='cd'前s的引用计数为1那么它才会被释放。我不知道我这么想是否正确,主要问题是在p:=pChar(s)是否会增加对s的引用次数?请给予我明确的答复,谢谢!
http://expert.csdn.net/Expert/topic/1798/1798183.xml?temp=4.923648E-02
这个问题你也回答过。也请大家看一下。总的来说,我可以使用指针什么的,但是对Delphi的内存管理方法还是糊里糊涂,比如说,new() dispose() getmem() freemem()等等我知道怎样用,但是我不知道它们都具体干了些什么,它们是怎样操作内存的。★★下面是我猜想的,请大家看看对不对???
我们知道,Delphi的内存分配方式与VC不同,Delphi的动态变量使用的内存是分配在堆中的,
var i: ^integer;
begin
new(i);
i^ := 5;
dispose(i);
end;
在new(i); i^ := 5;之后,i中保存的是5所在的那块内存的起始地址,5被分配在堆中并占据4个字节的内存空间。
dispose(i);之后,都干了些什么?我不知道。
我猜想:在dispose(i);之前程序是怎样知道5所在的那块内存是不能被分配的?是不是5所在的那块内存中有什么标记表明它正在被其他指针使用?
我猜想:dispose(i);之后,5仍然在那块内存中,只是标记被更改,表明这块内存没有被其他指针使用可以被再分配。而i中的地址值是不会变化的。
i所在的内存的地址应该是固定的,即使是对i重新赋值。大家可以用IntToStr(integer(@i))来检查一下。这一点与string类型的变量不一样,也许是因为string类型是生存期自管理的吧!我不明白?请各位老师确定或否定我的猜想,谢谢了!!!!!★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
---------------------------------------------------------
这样的理解不知对是不对?
当对string类型变量进行强制类型转换时,delphi同样会增加对它的引用计数,即经转换后得到pchar也拥有一个对原始string的引用计数。因为有这个引用对数的存在,所以当pchar的作用范围大于string时,它会阻止delphi提前释放string的内存。
----------------------------------------------------------------------------------
dispose(i);之后,5已经不在那块内存中
看一段代码就知道了
var i: ^integer;
addr:integer;
begin
new(i);
i^ := 5;
addr:=integer(i);
memo1.Lines.Add('i 指向的地址 '+inttostr(integer(i)));
memo1.Lines.Add('addre 的值 '+inttostr(addr));
memo1.Lines.Add('addre 指向的值 '+inttostr(pinteger(addr)^));
dispose(i);
memo1.Lines.Add(' ');
memo1.Lines.Add('dispose 之后');
memo1.Lines.Add('i 指向的地址 '+inttostr(integer(i)));
memo1.Lines.Add('addr 指向的值 '+inttostr(pinteger(addr)^)); i:=nil; memo1.Lines.Add(' ');
memo1.Lines.Add('nil 之后');
memo1.Lines.Add('i 指向的地址 '+inttostr(integer(i)));
memo1.Lines.Add('addr 指向的值 '+inttostr(pinteger(addr)^));end;
--------------------------------------------------------------------------
谢谢大家的关注,可是还是没有人能全面清楚的进行解释!!!!!!!!!
难道就要这样糊里糊涂下去吗???
只是会用,却不知道为什么这样???我不想这样下去!!!!!!!
这么多的人里就没有一个懂的吗???????
--------------------------------------------------------------------------
to:TreeLand() 《Delphi5 开发人员指南》上说:
“在练习将一个字符串转换为PChar类型时要小心,因为字符串在超出其作用范围时有自动回收的功能,”
从上面这句话理解,一个字符串转换为PChar类型时应该是不增加字符串的引用记数的,我也说不准,没看到哪本书上有明确的说明,哎!!!!
--------------------------------------------------------------------------
对string类型进行pchar类型的强制转换到底增不增加string类型变量的引用记数???我不知道?但是很关键。
--------------------------------------------------------------------------
to:itytramper(阿琪) 你的例子我还没有来得及上机实验,我只是看了看。
你的例子中 i指向的地址 和 addre的值 应该是一个值吧,如果想要取i的地址(不是i中保存的地址)应该用 integer(@i)吧?我不确定!等我上机实验一下再说。
--------------------------------------------------------------------------
to:Eastunfail(恶鱼杀手) ( ) 信誉:78 2003-06-09 19:57:00 懂就说出来嘛,别买关子了!说这么一句就走了啊!!不能放过你!!!
--------------------------------------------------------------------------
http://expert.csdn.net/Expert/topic/1798/1798183.xml?temp=.8233911procedure TForm1.Button1Click(Sender: TObject);
var i: ^integer;
begin
new(i);
i^ := 5;
dispose(i);
Edit1.Text := IntToStr(i^);//显示5
i^ := 6; // 为什么在dispose(i)之后执行它居然不会报错?
Edit2.Text := IntToStr(i^);//显示6
end;
{我对指针这块真是搞不懂,为什么执行dispose(i)之后,下面的语句居然还能正常执行并显示正确的结果呢?按理说,在执行dispose(i)之后,i就应该变成值无定义了,可是为什么i^还能指向5?并且5所在的那块内存不是应该被释放了吗?
谁能给我讲讲指针的结构。new,dispose都是怎样工作的,内存上是怎样管理的?
谢谢了!!}
dispose是告诉操作系统收回这块内存,可以另做它用。
这两种操作本身并不改变该内存中实际内容,所以即使释放后,也可以通过地址(指针)引用该地址,如其内容未被另的程序修改,是不会改变的。
http://www.pcvc.net/category/content.asp?sendid=114
http://www.pcvc.net/category/content.asp?sendid=118
强制类型转换只是得到了string[0]指针罢了
你这里string是临时变量 在stack中分配的内存
所以当返回时这个字符是被清除掉了
但是你的函数本身在调用时占用了调用者的堆内存所以
那时DELPHI会自动把这个字符串复制到调用者的堆内存中
所以生存期很重要 如果不是用函数本身返回
而用参数的话就会出错
那句话说的十分正确
i 指向的地址 13452928
addre 的值 13452928
addre 指向的值 5
dispose 之后
i 指向的地址 13452928
addr 指向的值 13452924
nil 之后
i 指向的地址 0
addr 指向的值 13452924
******************************************************************
这里i的地址是不变的,我们关心的是i里面的内容,也就是5的地址 addr ,和这个地址里的值 value
dispose以后,addr是不变的,value变成了13452924
只有i:=nil后addr才等于0 ***********************************************你的代码的结果
13443508 //在我的机子上并不是5
6 i^ := 6; // 为什么在dispose(i)之后执行它居然不会报错?
//这样是不安全的,这个地址的内存可能已经在别的地方用了
2、“因此当进行P:=PChar(Str)的赋值时,P的作用域(生存期)应当大于Str的作用域。”这话没错,这不是SmallHand(火龍)说的什么长度问题,而是,你的函数返回时,返回的指针指向的s1已经自动释放了!也就是说,这个函数只会引起程序出错!
多数人都(包括我本来)认为P=pchar(S)是对S的引用,至少,现在清楚,这是错的。Delphi是对S复制了另一份!
另外,不管内部机制如何,释放代码确实是没必要的。
S := '? ' + DateTimeToStr(Now);
P := PChar(S);
S[1] := '!';
ShowMessage(P);//此时显示的是S的新值!
S := S + S;
ShowMessage(P);//此时结果不可预测!现在非常清楚,PChar根本只是一个引用指针,指向的内存并不属于它,也不存在引用计数的问题,当然谈不上什么释放!
难道就要这样糊里糊涂下去吗???
只是会用,却不知道为什么这样???我不想这样下去!!!!!!!
这么多的人里就没有一个懂的吗???????
//说实话,我很反感楼主上面的某些言论。1+1=2 我们用了很多年,但如果有人正确的解释了为什么会是这样,我想可能不是每个人都能明白。建议楼主找一份object pascal 手册看看(置顶的那个地址我试了一下,失败),也许不能完全解答你的疑问,但至少能加深你delphi对字符串类型数据的管理方式。讨论的前提是有一定的基础设置水平相当,否则,只能叫学习.管见,仅供参考
我知道我菜,我就是来学习的。我可没想浪费你的时间。
和作者摘的含义正好相反。这句话的意思是这样的:字符串类型是具有自动回收功能的,但是字符串指针没有。P:=PChar(Str)返回的指针可能在作用域之外使用,因此P 的生存周期可能比Str 要长。举个例子来说明:
procedure getPChar(P: PChar);
var
strTmp: string;
begin
strTmp := 'asasass';
P := PChar(strTmp);
end; 这个时候,明显返回的这个指针P 的作用域要大于strTmp,那么这个过程结束的时候,strTmp已经被自动释放掉了。调用这个过程的函数得到的P 事实上已经是一个悬挂指针,没有意义了。作者的本意是提醒读者注意防止这样的情况发生。
书上就是那么写的,我没有记错!我看的是ChinaPub出的PDF格式的《Delphi5 开发人员指南》,这里面有不少的错误(翻译上的),如:书上的原代码注释上写着:自定义光标的序号应该小于0(大概是这句话,位置我忘了。)而我看原代码时发现注释中明明写着自定义光标的序号应该大于0。我倒!
不知道纸书上怎样?
运行下面的代码就可以清楚了!
S := '? ' + DateTimeToStr(Now);
P := PChar(S);
S[1] := '!';
ShowMessage(P);//此时显示的是S的新值!
S := S + S;
ShowMessage(P);//此时结果不可预测!现在非常清楚,PChar根本只是一个引用指针,指向的内存并不属于它,也不存在引用计数的问题,当然谈不上什么释放!这是非常正确的,另注意DELPHI为了兼容PChar,在string的最后自动加了'\0'。p:= pchar(s)只是返回s[0]的地址,不影响引用计数器。所以如果p的生存期超过s,则p不可预测。