string类型 的问题(200分)

  • 主题发起人 主题发起人 zlj555
  • 开始时间 开始时间
Z

zlj555

Unregistered / Unconfirmed
GUEST, unregistred user!
var
str1,str2 : string;
begin
str1 :='abc';
str2 :=str1;
end;
请问Str1与Str2是不是仅为一个字符串型的指针,而他们内容的存放空间位于同一处??
还是Str1与Str2即为存放的空间???????????????
希望能提出强有力的证据。
 
procedure TForm1.Button3Click(Sender: TObject);
var
a,b:string;
begin
a:='abc';
b:=a;
ShowMessage('变量a的地址是:$'+IntToHex(Integer(@a),2)+' 变量a的值是:'+String((@a)^)+' 变量b的地址是:$'+IntToHex(Integer(@b),2)+' 变量b的值是:'+String((@b)^));
a:='ddd';
ShowMessage('变量a的地址是:$'+IntToHex(Integer(@a),2)+' 变量a的值是:'+String((@a)^)+' 变量b的地址是:$'+IntToHex(Integer(@b),2)+' 变量b的值是:'+String((@b)^));
end;
 
我的理解是:
1、单纯的定义一个Stirng,那在引用过程中,系统来肯定会把所定义的字符串变量对应到一个指针上处理的。
2、如果想直接引用指针则用Pchar或直接定义指针类型。
我想关键看你怎么用。
 
没能看见强有力的证据,我可是在和别人赌呀。
 
//强有力的证据来了!如果你喜欢用指针的思想去理解,看看pstr中怎么玩的吧!^_^
procedure TForm1.Button4Click(Sender: TObject);
var
a,b:string;
pstr:^string;
begin
a:='abc';
b:=a;
ShowMessage('变量a的地址是:$'+IntToHex(Integer(@a),2)+' 变量a的值是:'+String((@a)^)+' 变量b的地址是:$'+IntToHex(Integer(@b),2)+' 变量b的值是:'+String((@b)^));
a:='ddd';
ShowMessage('变量a的地址是:$'+IntToHex(Integer(@a),2)+' 变量a的值是:'+String((@a)^)+' 变量b的地址是:$'+IntToHex(Integer(@b),2)+' 变量b的值是:'+String((@b)^));
pstr:=@a;
showmessage('pstr这个指针的内存地址:'+IntToHex(Integer(@pstr),2)+' pstr中所存的目标地址:'+IntToHex(Integer(pstr),2)+' pstr所指向的地址中所存的值为:'+pstr^);
pstr:=@b;
showmessage('pstr这个指针的内存地址:'+IntToHex(Integer(@pstr),2)+' pstr中所存的目标地址:'+IntToHex(Integer(pstr),2)+' pstr所指向的地址中所存的值为:'+pstr^);
end;
 
to peihexian :你的回答证明不了什么,如果a与b同为字符串指针,当然a与b的地址会不
不样,但是a与b所指向的地址空间是一样的。
当然你的a:='ddd'只不过是把新的地址空间赋给了a,

个人观点,希望高手的参与。
 
以我在C++ Builder中的观察来谈谈,
打开Debug Window -> Local Variables,可以看到,String是一种类,而不是简单数据类
型。当Str2 := Str1时,实际上只是将Str2的数据地址指向Str1的数据地址(两者的数据
地址是一样的),但两个对象本身的地址不一样,
 
to peihexian : 你弄来弄去什么没能证明呀??你的字符串型指针弄了一堆,开始我真还
昏了。但是一分析:如下。。
b:=a
变量a的地址是:$12F570 变量a的值是:abc 变量b的地址是:$12F56C 变量b的值是:abc
a:=ddd
变量a的地址是:$12F570 变量a的值是:ddd 变量b的地址是:$12F56C 变量b的值是:abc
pstr:=@a
//////以下不就是绕了个圈吗?根本没回到存储的内容的空间地址上(不是变量的地址)。??????????
pstr这个指针的内存地址:12F568 pstr中所存的目标地址:12F570 pstr所指向的地址中所存的值为:ddd
pstr:=@b
pstr这个指针的内存地址:12F568 pstr中所存的目标地址:12F56C pstr所指向的地址中所存的值为:abc
 
BCB的例子:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String a;
String b;
a="abc";
b=a;
ShowMessage("变量a的内存地址:$"+IntToHex(int(&a),2)+" 变量a的值为:"+String(*(&a))+" 变量b的内存地址为:$"+IntToHex(int(&b),2)+" 变量b的值为:"+String(*(&b)));
//改变a的值
a='aaa';
ShowMessage("变量a的内存地址:$"+IntToHex(int(&a),2)+" 变量a的值为:"+String(*(&a))+" 变量b的内存地址为:$"+IntToHex(int(&b),2)+" 变量b的值为:"+String(*(&b)));
}
变量a的内存地址:$12F580 变量a的值为:abc 变量b的内存地址:$12F57C 变量b的值为:abc
变量a的内存地址:$12F580 变量a的值为:6381921 变量b的内存地址:$12F57C 变量b的值为:abc
不知道为什么a的值变了以后会出现6381921,如果说a和b指向同一地址,则以上程序至少说明改变a的值后对b没有影响,如果说系统给a分配了新的内存,则如果
我们做一个这样的程序,运行一个小时后系统应该死机,即zlj555所说的分配新的内存将导致系统内存不足!
void __fastcall TForm1::Button2Click(TObject *Sender)
{
String a;
for(;;)
{
a="abc";
Application->ProcessMessages();
}
}
 
Str1与Str2是一个字符串型的指针! 请见<<Delphi5 开发人员指南>>的 "2.6.3 字符串"部分!
复制如下:
2.6.3 字符串
字符串是代表一组字符的变量类型,每一种语言都有自己的字符串类型的存储和使用方法。
P a s c a l类型有下列几种不同的字符串类型来满足程序的要求:
&#8226;
AnsiString 这是P a s c a l缺省的字符串类型,它由AnsiChar 字符组成,其长度没有限制,同时与
n u l l结束的字符串相兼容。
&#8226;
ShortString 保留该类型是为了向后兼容Delphi 1.0,它的长度限制在2 5 5个字符内。
&#8226;
WideString 功能上类似于A n s i S t r i n g,但它是由Wi d e C h a r字符组成的。
&#8226;
PChar 指向n u l l结束的C h a r字符串的指针,类似于C的char * 或l p s t r类型。
&#8226;
PAnsiChar 指向n u l l结束的A n s i C h a r字符串的指针。
&#8226;
PWideChar 指向n u l l结束的Wi d e C h a r字符串的指针。
缺省情况下,如果用如下的代码来定义字符串,编译器认为是AnsiString 字符串:
v a r
S:string;
//编译器认为S的类型是A n s i S t r i n g
当然,能用编译开关$ H来将s t r i n g类型定义为S h o r t S t r i n g,当$ H编译开关的值为负时, s t r i n g变量
是S h o r t S t r i n g类型;当$ H编译开关的值为正时(缺省情况),字符串变量是A n s i S t r i n g类型。下面的代码
演示了这种情况:
v a r
{ $ H - }
S1:string;
//S1是S h o r t S t r i n g类型
{ $ H + }
S2:string;
//S2是A n s i S t r i n g类型
使用$ H规则的一个例外是,如果在定义时特地指定了长度(最大在2 5 5个字符内),那么总是
S h o r t S t r i n g:
v a r
S: string[63];
//63个字符的S h o r t S t r i n g字符串
1. AnsiString类型
A n s i S t r i n g (或长字符串)类型是在Delphi 2.0开始引入的,因为Delphi 1.0的用户特别需要一个容易
使用而且没有2 5 5个字符限制的字符串类型,而A n s i S t r i n g正好能满足这些要求。
虽然A n s i S t r i n g在外表上跟以前的字符串类型几乎相同,但它是动态分配的并有自动回收功能,正
是因为这个功能A n s i S t r i n g有时被称为生存期自管理类型。Object Pascal能根据需要为字符串分配空间,
所以不用像在C / C + +中所担心的为中间结果分配缓冲区。另外, A n s i S t r i n g字符串总是以n u l l字符结束
的,这使得A n s i S t r i n g字符串能与Win32 API 中的字符串兼容。实际上,A n s i S t r i n g类型是一个指向在堆
栈中的字符串结构的指针。
警告Borland没有将长字符串类型的内部结构写到文档中,并保留了在Delphi后续版本中修改
长字符串内部格式的权利。在这里介绍的情况主要是帮助你理解A n s i S t r i n g类型是怎样工作的
并且在程序中要避免直接依赖于AnisString结构的代码。
程序员如果在Delphi 1.0中避免了使用字符串的内部结构,则把代码移植到Delphi 2.0没有
任何问题。而依赖于字符串内部结构写代码的程序在移植到Delphi 2.0时必须修改。
正如图2 - 1演示的,A n s i S t r i n g字符串类型有引用计数的功能,这表示几个字符串都能指向相同的
物理地址。因此,复制字符串因为仅仅是复制了指针而不是复制实际的字符串而变得非常快。
图2-1 显示了AnsiString在内存中分配的情况
当两个或更多的A n s i S t r i n g类型共享一个指向相同物理地址的引用时, D e l p h i内存管理使用了
c o p y - o n - w r i t e技术,一个字符串要等到修改结束,才释放一个引用并分配一个物理字符串。下面的例
子显示了这些概念:
v a r
S 1 , S 2 : s t r i n g ;
b e g i n
/ /给S 1赋值,S 1的引用计数为1
S1:='And now for something...';
S2:=S1;
//现在S 2与S 1指向同一个字符串, S 1的引用计数为2
/ / S 2现在改变了,所以它被复制到自己的物理空间,并且S 1的引用计数减1
S2:=S2+'completely diff e r e n t 1 ' ;
e n d ;
生存期自管理类型
除了A n s i S t r i n g以外, D e l p h i还提供了其他几种生存期自管理类型,这些类型包括:
Wi d e S t r i n g、Va r i a n t、O l e Va r i a n t、i n t e r f a c e、d i s p i n t e r f a c e和动态数组,这些类型在本章稍后有
介绍,现在,我们重点讨论究竟什么是生存期自管理,以及它们是如何工作的。
生存期自管理类型,又被称为自动回收类型,是指那些在被使用时就占用一定的特殊资
源,而在它离开作用域时自动释放资源的类型。当然不同的类型使用不同的资源,例如,
A n s i S t r i n g类型在被使用时就为字符串占用内存,当它超出作用域时就释放被字符串占用的内
存。
 
to zlj555:
高人给了我答案:
string可以理解成一个指针,它指向存放字符串内容的内存地址的起始点。在这个起始点的前方几个字节,存放着字符串长度及引用数(reference count)。Delphi Object Pascal就靠这个实现string的智能管理,
以及"Copy on write"(写复制)机能。
当执行
str1:='aaa';
str2:=str1;
时,首先会分配一段空间给str1,填写'aaa'内容,长度设置为3,引用数为1,然后修正str2的指向,使之与str1一致,
并且在内存中reference count地址处将引用数加1。如果此后执行了
str2:='kkk';
此时因为原先str2所指向的'aaa'的引用数大于1,则需要扣除其一个引用数,
然后新分配一段空间给str2,在空间中填写上'kkk'内容……等等
我输了!
 
接受答案了.
 
在delphi中string 类型实际上是一个指向在堆栈中的字符串结构的指针,它具有引用记数
的功能,这表示几个字符串都能指向相同的物理地址。因此,复制字符串仅仅复制了指针而
不是复制实际的字符串。
var
str1,str2 : string;
begin
str1 :='abc';
str2 :=str1;
//现在str1和str2指向同一个字符串,且str1的引用记数为2
end;
调试时候把view cpu 调出来可以看到赋值过程两个变量是指向同一地址的
应该可以证明了吧
 
后退
顶部