文档章节

深入 Delphi 的字符串类型

天朝八阿哥
 天朝八阿哥
发布于 2017/08/15 23:17
字数 826
阅读 24
收藏 0

前几天的文章中提到了 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. 字符串在进行拼接时,拼接后的字符串是在另一段完全不同的内存空间中,而且是在堆区。由于堆栈性质的不同,堆的执行效率不如栈,因此,当进行大量的字符串拼接时,这将会成为性能瓶颈之一。

© 著作权归作者所有

天朝八阿哥

天朝八阿哥

粉丝 1
博文 23
码字总数 17659
作品 0
郑州
程序员
私信 提问
用好Delphi中的字符串

用好Delphi中的字符串日期:2005年10月18日 作者: 人气:17184 查看:[大字体 中字体 小字体]一:各种字符串  字符串是Object Pascal所有数据类型中最有用的类型。许多函数以字符串为传递参...

vga
2016/08/09
41
0
最基础的数据结构-左轻侯

作者:左轻侯 创建时间:2007-03-04 22:29:06 最后修改时间:2008-01-18 22:07:52 本文发表于《程序员》2007年第3期      最基础的数据结构   左轻侯   2007.2.3      引言   ...

一配
2015/10/16
51
0
[转] Java中调用Delphi编写的DLL

有些时候,要写一些程序,在 JAVA 里面好难实现, 但如果使用其它编程语言却又比较容易时,我们不妨通过 JNI 来让不同语言的程序共同完成. JNI 的教程, 网上 C 的比较多,Java 也提供了 javah.ex...

鉴客
2010/10/28
2.8K
1
Java中调用Delphi编写的DLL

有些时候,要写一些程序,在 JAVA 里面好难实现, 但如果使用其它编程语言却又比较容易时,我们不妨通过 JNI 来让不同语言的程序共同完成. JNI 的教程, 网上 C 的比较多,Java 也提供了 javah.ex...

geek_loser
2014/09/26
824
0
delphi pchar char byte string转换问题

delphi pchar char byte string转换问题 注:Delphi中的Char,PChar,PByte,Byte,String的相互转换,您是不是也遇到过,为此头疼过吗?你要是明白了他们的原理就会轻松了。 话题064840的标题是...

鹅倌
2017/01/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SDKMAN推荐一个好

是在大多数基于Unix的系统上管理多个软件开发工具包的并行版本的工具。它提供了一个方便的命令行界面(CLI)和API来安装,切换,删除和列出sdk相关信息。以下是一些特性: By Developers, fo...

hotsmile
25分钟前
8
0
什么是 HDFS

是什么? HDFS 是基于 Java 的分布式文件系统,允许您在 Hadoop 集群中的多个节点上存储大量数据。 起源: 单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称...

Garphy
28分钟前
4
0
一起来学Java8(四)——复合Lambda

在一起来学Java8(二)——Lambda表达式中我们学习了Lambda表达式的基本用法,现在来了解下复合Lambda。 Lambda表达式的的书写离不开函数式接口,复合Lambda的意思是在使用Lambda表达式实现函...

猿敲月下码
54分钟前
10
0
debian10使用putty配置交换机console口

前言:Linux的推广普及,需要配合解决实际应用方能有成效! 最近强迫自己用linux进行实际工作,过程很痛苦,还好通过网络一一解决,感谢各位无私网友博客的帮助! 系统:debian10 桌面:xfc...

W_Lu
今天
10
0
aelf Enterprise 0.8.0 beta有奖公测,“Bug奖金计划”重磅开启

2019年9月30日,aelf Enterprise 0.8.0 beta版正式发布。aelf Enterprise 0.8.0 beta是一个完备的区块链系统, 包含完备的区块链系统、开发套件、开发文档、以及配套的基础应用和基础服务。 ...

AELF开发者社区
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部