深入 Delphi 的字符串类型

前几天的文章中提到了 Delphi 的字符串,但并未展开说,这里就详细探讨下 Delphi 的字符串类型。

废话不多说,直接上源码:

program StringTest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  s1, s2, s3: string;

begin
  Writeln('Now time : ',FormatDateTime('HH:MM:SS.ZZZ',Now()));
  Writeln('--------------------------------');
  Writeln('s1       = ', s1);
  Writeln('@s1      = ', Cardinal(@s1));
  Writeln('@s1[1]   = ', Cardinal(@s1[1]));
  Write('Input s1 : ');
  Readln(s1);
  Writeln('s1       = ', s1);
  Writeln('@s1      = ', Cardinal(@s1));
  Writeln('@s1[1]   = ', Cardinal(@s1[1]));
  Writeln('--------------------------------');
  s2 := 'Hello ';
  s3 := 'Delphi ';
  Writeln('s2       = ', s2);
  Writeln('s3       = ', s3);
  Writeln('@s2      = ', Cardinal(@s2));
  Writeln('@s3      = ', Cardinal(@s3));
  Writeln('@s2[1]   = ', Cardinal(@s2[1]));
  Writeln('@s3[1]   = ', Cardinal(@s3[1]));
  Writeln('--------------------------------');
  s2 := s2 + s3;
  Writeln('s2 := s2 + s3');
  Writeln('s2       = ', s2);
  Writeln('s3       = ', s3);
  Writeln('@s2      = ', Cardinal(@s2));
  Writeln('@s3      = ', Cardinal(@s3));
  Writeln('@s2[1]   = ', Cardinal(@s2[1]));
  Writeln('@s3[1]   = ', Cardinal(@s3[1]));
  Writeln('--------------------------------');
  s3 := s2 + s3;
  Writeln('s3 := s2 + s3');
  Writeln('s2       = ', s2);
  Writeln('s3       = ', s3);
  Writeln('@s2      = ', Cardinal(@s2));
  Writeln('@s3      = ', Cardinal(@s3));
  Writeln('@s2[1]   = ', Cardinal(@s2[1]));
  Writeln('@s3[1]   = ', Cardinal(@s3[1]));
  Readln;
end.

运行结果如下:

从运行结果可以看出:

  1. 字符串类型实际是分两部分进行保存的,一部分是字符串变量名(本质是指针),另一部分是字符串内容(本质是字符串数组,且第0个元素存放的是字符串的长度)。
  2. 字符串在未初始化/未赋值时,字符串内容的地址为0,即系统未对其进行分配内存;但字符串变量名的地址是存在的,可以理解为字符串变量已经完成了占位工作,方便后续工作的展开。
  3. 字符串在赋值、拼接时,变量名地址不变,内容地址改变,说明后来的字符串内容是在另外一个位置重新生成的新字符串,和原来的字符串没有任何关系。
  4. 字符串变量名的地址远小于字符内容的地址,说明两者是在完全不同的内存区域。事实上,字符串变量名是在栈区,字符串内容是在堆区。

过一段时间之后再次运行,结果如下:

对比两次运行,可以看出:

字符串变量名地址未发生变化,字符串内容地址却完全不同,进一步说明变量名是分配在栈区,内容是分配在堆区。

至于是在程序的栈区和堆区还是在内存的栈区和堆区,暂不可知。因此又先后把该测试程序打开两次,把该测试程序复制一个副本几乎同时打开,运行结果如下图:

由此可以看出:

  1. 变量名确实是分配在栈区,而内容是分配在堆区。
  2. 这里的栈区和堆区,极有可能是内存的栈区和堆区,但也不排除是 Delphi 专门做过优化的原因。

结论:

  1. 字符串变量名分配在栈区,内容分配在堆区。
  2. 字符串未初始化/未赋值时,Delphi 只为变量名分配了内存空间,为字符串赋值时才为内容分配内存空间。
  3. 字符串在进行拼接时,拼接后的字符串是在另一段完全不同的内存空间中,而且是在堆区。由于堆栈性质的不同,堆的执行效率不如栈,因此,当进行大量的字符串拼接时,这将会成为性能瓶颈之一。

转载于:https://my.oschina.net/u/209067/blog/1510789

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值